android Jetpack组合重新组合争用条件

yruzcnhs  于 2022-11-27  发布在  Android
关注(0)|答案(2)|浏览(185)

假设我们有下面的代码,它显示一个按钮,当用户点击它时,按钮消失。

@Composable
fun ButtonThatDisappearsOnClick() {
    var showButton by remember { mutableStateOf(true) }
    if (showButton) {
        Button(onClick = {
            check(showButton) { "onClick shouldn't be called for a hidden button" }  // !!!
            showButton = false
        }) {
            Text("My button")
        }
    }
}

我怀疑,如果用户非常快速地单击按钮 * 两次 *,上面的check调用可能会失败:

  • 用户单击该按钮,shouldShowButton被设置为false。由于处于可变状态的值被更新,因此调度了重组。
  • 用户再次快速点击按钮,视图重组之前,onClick函数将第二次触发,check调用将失败。

我一直无法在实践中重现这种情况,所以我想知道这样的行为是否确实可能。

mnemlml8

mnemlml81#

这个问题是你所要求的答案。操作连续地改变值,但是如果状态值在重组完成之前改变,则有可能丢弃先前的重组并调度新的重组。
MutableState ignores first value if set two values in a row
SideEffect函数可用于仅当成功重组时才应调用的操作
只要Compose认为可组合对象的参数可能已更改,就会启动重新组合。重新组合是乐观的,这意味着Compose希望在参数再次更改之前完成重新组合。如果参数在重新组合完成之前发生更改,Compose可能会取消重新组合,并使用新参数重新启动。
取消重新组合时,撰写会舍弃重新组合的UI树形结构。如果您有任何副作用,而该副作用取决于所显示的UI,则即使取消撰写,也会套用该副作用。这可能会导致应用程序状态不一致。
确保所有可组合函数和lambda都是幂等的,并且没有副作用,以处理乐观重组。

hpcdzsge

hpcdzsge2#

这是可能的。不太可能发生,但也是可能的。在实践中,快速单击或双击问题存在于组合中。在这个特定的情况下,这可能发生,因为示例可组合程序正在保持某种状态。
有一种做法是使组合变得无状态,并将状态保持在外部。组合将能够检测特定重组流外部的参数更改,并可能取消它。(在您的情况下,它不会隐藏按钮,因此您不会达到意外的行为)
来自官方documentation
只要Compose认为可组合对象的参数可能已更改,就会启动重新组合。重新组合是乐观的,这意味着Compose希望在参数再次更改之前完成重新组合。如果参数在重新组合完成之前发生更改,Compose可能会取消重新组合,并使用新参数重新启动。

相关问题