【发布时间】:2022-06-15 04:35:35
【问题描述】:
我在这里遇到了一个非常奇怪的问题。我有一个ViewModel 有一个StateFlow。 ViewModel 在特定情况下重新创建,并将其 StateFlow 值设置为 0。
我还有一个 Compose 视图,它读取这个 StateFlow 的值并根据它显示文本。
例如,然后我将该状态更改为 2。然后重新创建整个 Compose 视图和ViewModel。
但是,当我重新创建整个视图时,ViewModel 在短时间内,StateFlow 保持它的旧状态(即使 ViewModel 与视图一起重新创建并且状态设置为 0),并且然后切换到新的零(这仅在您进行下面提到的更改时才有效)。
如果我们的列表具有不同数量的项目,这可能会导致崩溃,并且我们在重新创建视图时传递它们,因为这样我们将读取不存在的索引值并且我们的应用程序将崩溃。
将列表ViewModelTwo(mutableListOf("text4")) 更改为ViewModelTwo(mutableListOf("text4", "text5", "text6")) 将停止崩溃。但是看看日志,你就会知道发生了什么。首先它变为 2,然后变为 0,这是默认值。
我为 Compose-Jb 设置了 github 存储库。可以在 Android Studio 中打开:https://github.com/bnovakovic/composableIssue
很抱歉使用了 android compose 标签,但我找不到 Compose-JB 标签。 为方便起见,这里是代码 sn-ps。
感谢任何帮助
Main.kt
@Composable
@Preview
fun App(viewModelOne: ViewModelOne) {
val showComposable by viewModelOne.stateOne.collectAsState()
MaterialTheme {
// Depending on the state we decide to create different ViewModel
val viewModelTwo: ViewModelTwo = when (showComposable) {
0 -> ViewModelTwo(mutableListOf("text1", "text2", "text3"))
1 -> ViewModelTwo(mutableListOf("text4"))
else -> ViewModelTwo(mutableListOf("blah1", "blah2", "blah3"))
}
// New composable is always created with new ViewModelTwo that has default index of 0, yet the app still crashes
TestComposableTwo(viewModelTwo)
Row {
Button(onClick = {
viewModelOne.changeState()
}) {
Text("Click button below, than me")
}
}
}
}
fun main() = application {
Window(onCloseRequest = ::exitApplication) {
val viewModelOne = ViewModelOne();
App(viewModelOne)
}
}
TestComposableView
@Composable
fun TestComposableTwo(viewModelTwo: ViewModelTwo) {
val currentIndex by viewModelTwo.currentListItem.collectAsState()
println("Index is: $currentIndex")
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.fillMaxWidth()
.fillMaxHeight()
) {
// At the point where we recreate this composable view, currentIndex keeps it's old value, and then changes it
// to the new one causing the app to crash since new list does not have index of 1
Text(text = viewModelTwo.stringList[currentIndex])
Button(onClick = {
viewModelTwo.changeIndex()
}) {
Text("Click me before clicking button above")
}
}
}
ViewModel1
class ViewModelOne {
private val viewModelScope = CoroutineScope(Dispatchers.IO)
private val _stateOne = MutableStateFlow(0)
val stateOne = _stateOne.asStateFlow()
fun changeState() {
viewModelScope.launch {
val currentValue = stateOne.value + 1
_stateOne.emit(currentValue)
}
}
}
ViewModel2
class ViewModelTwo(val stringList: List<String>) {
private val viewModelScope = CoroutineScope(Dispatchers.IO)
private val _currentListItem = MutableStateFlow(0)
val currentListItem = _currentListItem.asStateFlow()
fun changeIndex() {
viewModelScope.launch {
_currentListItem.emit(2)
}
}
}
【问题讨论】:
标签: android-jetpack-compose android-jetpack