JetPack Compose 中的副作用

Rit*_*esh 3 android side-effects android-jetpack android-jetpack-compose

虽然我理解或认为我理解,喷气背包有哪些副作用。

It's any work done in composable which escapes the scope of the composable function
Run Code Online (Sandbox Code Playgroud)

我理解做诸如 I/O 操作或在函数作用域之外改变变量、提供引用而不清除它(内存泄漏)或改变不可组合状态的局部变量之类的事情 - 这些都是副作用,因为它们可以由于重组而导致意外行为和泄漏,重组是不确定的并且可以运行多次。为了解决副作用,我们有效果处理程序。

考虑到上述所有内容,我需要在一些情况下进行一些澄清

  • 副作用 - 如果对象发生变化,它是否适用于除组合对象之外的任何对象?正如在组合状态(mutableStateOf 等..)中不会导致副作用?为什么?
  • 为什么回调/状态/事件提升到您的活动/片段/视图模型不会导致副作用?

例如

@Composable
fun MyComposable(
viewModel:MyViewModel,
launchSomeActivity:()->Unit
){
   var state by remember { mutableStateOf("") }
   state = "some string" // not a side-effect?

   viewModel.someStringObject = "a" // it's a side-effect?

   launchSomeActivity() // it's a side-effect?

   when(val screenState = viewModel.screenState.collectAsState().value){
      is ScreenState.Success -> launchSomeActivity() // not a side-effect. why?
      is ScreenState.Error -> state="some String" // not a side-effect. why?
   }
}
Run Code Online (Sandbox Code Playgroud)

我还记得在某处读过,触发回调的副作用,例如onClick总是在 UI 线程上执行,或者说从 ViewModel 调用一些 lambda。

还想了解上述场景,例如它如何防止副作用、调用 lambda 或回调?

chu*_*ckj 5

SideEffect并不意味着其他任何东西都不是副作用。它是一个逃生舱口,用于应对应该考虑的事物和组合的效果,但没有或不能在节点树中表达。

例如,Dialog用于SideEffect将对话框属性、布局方向和从Dialog参数传递到作为组合结果创建的 Android 对话框的关闭回调。这呈现出一种错觉,它Dialog本身就是 Compose 的一部分,尽管它使用视图系统来创建对话框。

一般来说,组合函数应该只读取状态,而不应该修改状态。如果它确实修改状态,则应该仅修改在组合期间创建的状态,并由创建状态的可组合函数直接调用的可组合函数使用;并且仅在任何孩子阅读该状态之前,而不是之后。

副作用 - 如果对象发生变化,它是否适用于除组合对象之外的任何对象?正如在组合状态(mutableStateOf 等..)中不会导致副作用?为什么?

可组合函数应该只读取这些对象中的状态;它不应该修改这个状态。对于可观察状态,例如mutableStateOf,Compose 会观察此状态的更改,并安排读取该状态的可组合函数的重组。您可以使用它mutableStateOf来执行副作用;你不应该。

为什么回调/状态/事件提升到您的活动/片段/视图模型不会导致副作用?

如果使用得当,不会;不是从 Compose 的角度来看。组合函数是从读取的数据到用户界面树的转换函数。随着视图模型的更改,转换会逐渐重新评估,以生成视图模型的新状态所隐含的 UI。状态提升允许应用程序的较高级别部分对如何存储和/或验证数据有更多上下文,以控制应用程序的较低级别、更通用部分的状态。具有提升状态的组件永远不应该写入该状态。如果他们需要更改状态,他们应该使用新的所需状态或要进行哪些更改的描述来调用事件处理程序(例如DeleteCustomer #1234)。应该由提供的事件处理程序来实际更改提升状态。

state = "some string" // not a side-effect?

不它不是。它初始化state时状态不会转义,组合被视为组合的一部分。这不是推荐的做法,但它不是副作用。

launchSomeActivity()

这是一个副作用,应该执行,LaunchEffect以便在某个范围内启动协同例程,当组合中不再调用组合函数时,该范围将自动取消。

is ScreenState.Success -> launchSomeActivity() // not a side-effect. why?

这是出于相同原因和相同答案的副作用。

is ScreenState.Error -> state="some String" // not a side-effect. why?

这不是如上所述的副作用(即副作用意味着它对组合之外的某些东西有影响,但事实并非如此),但是,如果state已经被读取,那么它被认为是向后写入并且强烈不鼓励因为它可能会导致构图重复,也许是无限期地重复;因为任何已经读取的内容都可能会被重新安排再次执行。