Android Jetpack Compose mutableStateListOf not doing Recompo



那么,我在viewModel中有一个mutableStateListOf:

var childTravellersList = mutableStateListOf<TravellersDetails>()

TravellersDetails是一个具有error字段的数据类。

childTravellersList在UI中用作:

val list = remember{viewModel.childTravellersList}
LazyColumn(state = lazyColumnState) {
itemsIndexed(list) { index, item ->
SomeBox(show = if(item.error) true else false)
}
}

我在viewModel中写了一个函数,在给定childTravellersListindex时更新TravellersDetails的error为:

fun update(index){
childTravellersList[index].error = true
}

所以,无论何时我调用这个函数,列表都应该被更新。

这会更新列表,但不会触发UI重组😕。我哪里做错了?

mutableStateListOf只能通知添加/删除/替换列表中的某些元素。当你改变列表中的任何类时,可变状态无法知道它。

数据类非常适合在单向数据流中存储不可变状态,因为您总是可以"更改"。它使用copy,而您看到需要将新数据传递给视图或可变状态。因此,避免在数据类中使用var变量,始终将它们声明为val以防止此类错误。

var childTravellersList = mutableStateListOf<TravellersDetails>()
fun update(index){
childTravellersList[index] = childTravellersList[index].copy(error = true)
}

另一个问题是你正在使用val list = remember{viewModel.childTravellersList}:它保存第一个列表值并防止将来更新。使用ViewModel你可以直接使用它itemsIndexed(viewModel.childTravellersList)

只有当您更改列表本身时才会发生重组。你可以这样做。

var childTravellersList by mutableStateOf(emptyList<TravellersDetails>())
fun update(indexToUpdate: Int) {
childTravellersList = childTravellersList.mapIndexed { index, details ->
if(indexToUpdate == index) details.copy(error = true)
else details
}
}

同样,您不需要像在这里val list = remember{viewModel.childTravellersList}那样在您的可组合列表中记住此列表。由于MutableState在视图模型内部,它将始终在所有重组中存活。只要在LazyColumn中使用viewModel.childTravellersList即可。

使用单一触发机制来更新您的可组合。您的列表应该只是作为一个普通变量可用。您可以添加/删除/删除列表中的项目,甚至可以更新每个项目的属性。一旦对列表进行了这些更新,您就可以通过生成一个随机数来重新组合可组合对象,该随机数绑定到可组合对象中观察到的可变状态可观察对象:

芬兰湾的科特林:

class MyViewModel: ViewModel() {
var childTravellersList = mutableListOf<TravellersDetails>()
var onUpdate = mutableStateOf(0)
private fun updateUI() {
onUpdate.value = (0..1_000_000).random()
}
fun update(index){
childTravellersList[index].error = true
updateUI()
}
}
@Composable
fun MyComposableHandler() {
// This will detect any changes to data and recompose your composable.
viewmodel.onUpdate.value

MyComposable(
travelersList = viewmodel.childTravellersList
)
}
@Composable
fun MyComposable(
travelersList: List<TravellersDetails>
) {

}

您应该避免在视图模型中为需要更新的不同变量创建多个可变状态变量。绝对没有必要这样做。只需创建一个可变状态变量,如上所示。每当需要重新组合可组合对象时,只需使用updateUI函数。视图模型中的逻辑应该决定需要更新的内容,但将实际的更新机制留给单个可变状态可观察对象。这是一个干净的模式,将使更新可组合物更容易。

然而,一定要记住,你的UI通常是由层次结构中的许多可组合组件组成的。当只有一个元素发生变化时,您不希望重新组合整个层次结构。因此,对于每个需要独立于层次结构中的其他可组合对象进行重组的可组合对象,应该使用可变状态可观察对象。

使用上述解决方案的另一个好处是,您可以轻松地更新对象,而无需创建新对象。如果你想让你的可组合对象在对象的某个属性发生变化时重新组合,你就不能使用可变状态可观察对象,因为它们只检测对象本身的变化,而不检测对象的属性。这就是为什么您最好使用上面所示的触发方法,并在可组合物重新组合时简单地检索更新的对象。

如果你可以不使用data class,你可以看看这个

State in ViewModel是一个非常好的教程,它解释了如何管理列表。下面的代码片段来自教程:

有两种方法可以解决这个问题:
  1. 更改我们的数据类WellnessTask,使checkedState变为MutableState而不是Boolean,这会导致Compose to跟踪项目变化。
  1. 复制你要变异的项目,移除项,并将突变项重新添加到列表中,其中使Compose跟踪该列表更改。

相关内容

最新更新