当按下C键时,这个应用程序计算A。由于A是唯一改变的,我期望重组就是这样。但是C也是重组。
下面是代码。
ViewModel公开状态流。
class MainViewModel : ViewModel() {
private val _count: MutableStateFlow<Int> = MutableStateFlow(0)
val count: StateFlow<Int> = _count.asStateFlow()
fun increaseCount() {
_count.value++
}
}
CCompose
调用increaseCount()
。
@Composable
fun CountUpScreen(
modifier: Modifier = Modifier,
viewModel: MainViewModel = viewModel(),
) {
val count: Int by viewModel.count.collectAsState()
SideEffect { println("CountUpScreen") }
Column(
modifier = modifier.fillMaxSize(),
verticalArrangement = Arrangement.SpaceEvenly,
horizontalAlignment = Alignment.CenterHorizontally,
) {
ACompose(
count = count
)
BCompose()
CCompose {
viewModel.increaseCount()
}
}
}
@Composable
private fun ACompose(count: Int) {
SideEffect { println("ACompose") }
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally) {
Text(
text = "$count"
)
}
}
@Composable
private fun BCompose() {
SideEffect { println("BCompose") }
Text(
text = "I am composable that will not be recompose"
)
}
@Composable
private fun CCompose(onClick: () -> Unit) {
SideEffect { println("CCompose") }
Button(onClick = {
onClick()
}) {
Icon(Icons.Outlined.Add, contentDescription = "+")
}
}
以下是进行累加的日志的结果。
I/System.out: CountUpScreen
I/System.out: ACompose
I/System.out: CCompose
CCompose为何要重新撰写?
1条答案
按热度按时间deyfvvtc1#
这里发生了一些事情。
首先,Compose编译器不会自动记住捕获不稳定类型的lambda。ViewModel是一个不稳定的类,因此在onClick lambda中使用它来捕获它意味着每次重组时都将重新创建
onClick
。因为lambda正在被重新创建,所以
CCompose
的输入在各个重构中不相等,因此CCompose
被重构。这是Compose编译器的当前行为,但将来很可能会改变,因为我们知道这是一种常见的情况,我们可以做得更好。
如果你想解决这个问题,你可以自己记住lambda。
或者将ViewModel更改为具有lambda而不是increaseCount函数。
或者您可以在技术上使用@Stable对ViewModel类进行注解,但我可能不推荐这样做,因为正确维护稳定契约将非常困难。
但我也想提一下,如果
CCompose
只是一个小的可组合组件,那么额外的一次重新组合可能不会对应用的性能产生太大影响,只有当它确实给你带来了问题时,你才会应用这些修复。稳定性是一个相当大的主题,我建议阅读this post了解更多信息。