我似乎没有找到这个简单案例的解释。 一些简单的东西,比如持有逆流的视图模型:
class TestCounter : ViewModel() {
private val _counter = MutableStateFlow(0)
val counter = _counter.asStateFlow()
init {
viewModelScope.launch {
while (true){
delay(1000)
_counter.update {
it + 1
}
}
}
}
}
还有一个可组合函数,每次将其收集的状态值传递给另一个函数时,它都会自行重组。如果我将状态对象本身传递给另一个函数,则不会进行重组。虽然我读到这不是最佳实践。
@Composable
fun App() {
val testCounter = TestCounter()
val counter = testCounter.counter.collectAsState()
SideEffect {
println("RECOMPOSING EVERY TIME IF PASSING VALUE")
}
DrawCount(counter.value)
// DrawCount(counter)
}
我想念这里的一些东西。如果这是正常行为,那么我将如何使用委托(by)或用于 UI 状态的数据类来保存不同函数的一堆值。它总是会导致不必要的重组。 值稳定与否并不重要。
规则很简单:每个读取 State 对象值的可组合项都会在该值发生变化时再次执行。
您的
App
可组合项读取 counter
状态的值,以便将其传递给 DrawCount
。当counter
每秒都在变化时,那么App
每秒都需要重新组合。一切都很好。如果您将权力委托给国家并不重要,这只会在幕后做同样的事情。
但这并不是不必要的,因为每次重组时
DrawCount
都会使用新值再次执行。这很重要,否则该可组合项将无法更新。
您可以将代码包装在
remember
语句中以在重组期间跳过它。这就是 collectAsState
在内部完成的操作,因此实际上不会第二次收集流量。
唯一需要关心的是如何创建视图模型。通过使用
TestCounter()
,您可以在每次重组时(在本例中为每秒)创建一个新实例。计数器再次启动(从0开始),旧的计数器与旧的视图模型一起被丢弃。
您想要的是始终获得相同的视图模型实例。将其包装在
remember
中是不够的,因为视图模型需要比可组合项的寿命更长。所有被 remember
编辑的东西只能在重组后存活,当可组合项离开组合时它就不会存活。但是,视图模型应该仍然相同,以便当可组合项再次进入合成时,您将获得上次获得的相同实例。
这就是为什么 Compose 框架为您提供了一个特殊的
viewModel()
函数来为您完成所有这些工作。
如果您需要
TestCounter
的实例,正确的方法是:
val testCounter: TestCounter = viewModel()