喷气背包组合可变状态列表在更改列表项类中的属性值时不会触发重新组合



我想我这里缺少了Jetpack Compose的一个核心概念。当我试图更改可组合文件内部的non-constructordata classproperty时,遇到了一个问题,而该可组合文件是观察列表的一部分。

不起作用:(sadProperty未在构造函数中声明(

data class IntWrapper(val actualInt: Int = 0) {
var sadProperty: Int = 0
}
@Preview
@Composable
fun test() {
var state by remember { mutableStateOf(listOf(IntWrapper(1), IntWrapper(2), IntWrapper(3),IntWrapper(4)))}
fun onClick(item: IntWrapper) {
val indexOf = state.indexOf(item)
val newState = state.minus(item).toMutableList()
val copy = item.copy()
copy.sadProperty = Random.nextInt()
newState.add(indexOf, copy)
state = newState
}

Column() {
for (item in state) {
Text("ac: ${item.actualInt} sad: ${item.sadProperty}", modifier = Modifier.clickable { onClick(item)})
}
}
}

作品:(actualInt在构造函数中声明(

data class IntWrapper(var actualInt: Int = 0) {
var sadProperty: Int = 0
}
@Preview
@Composable
fun test() {
var state by remember { mutableStateOf(listOf(IntWrapper(1), IntWrapper(2), IntWrapper(3),IntWrapper(4)))}
fun onClick(item: IntWrapper) {
val indexOf = state.indexOf(item)
val newState = state.minus(item).toMutableList()
val copy = item.copy()
copy.actualInt = Random.nextInt()
newState.add(indexOf, copy)
state = newState
}

Column() {
for (item in state) {
Text("ac: ${item.actualInt} sad: ${item.sadProperty}", modifier = Modifier.clickable { onClick(item)})
}
}
}

有人能解释一下为什么会发生这种情况吗?

这看起来像是Jetpack Compose和关于Kotlin数据类的问题,我会尽力的。

让我们首先从Kotlin的数据类开始

根据关于Data Class的kotlin文件

编译器自动从所有在主构造函数中声明的属性:

  • equals((/hashCode((对
  • toString((的形式;用户(姓名=John,年龄=42(">
  • componentN((函数,这些函数按声明顺序与属性相对应
  • copy((

您的IntWrapper数据类有一个主构造函数,类名后面的括号,其中声明了1个属性。

data class IntWrapper(val actualInt: Int = 0) {
var sadProperty: Int = 0
}

这样,我们可以说,您的IntWrapper数据类具有

  • 1组分(actualInt(
  • 形式为IntWrapper(actualInt=?)的toString((
  • 生成的CCD_ 13函数
  • 生成的equals((/hashCode((对

并且再次基于文档:

编译器仅使用在主构造函数。排除属性,在类主体:

equals将仅使用/评估从IntWrapper's主构造函数(即actualInt : Int(声明的属性,并且sadProperty被排除在外,因为它位于数据类主体的部分。

现在考虑以下内容:

val intWrapper1 = IntWrapper(actualInt = 5)
intWrapper1.sadProperty = 5
val intWrapper2 = IntWrapper(actualInt = 5)
intWrapper2.sadProperty = 10
Log.e("AreTheyEqual?", "${intWrapper1 == intWrapper2}")

它打印,

E/AreTheyEqual?: true

因为equality看到两个导出属性具有相同的值5,所以sadProperty被排除在该比较之外。

val intWrapper1 = IntWrapper(actualInt = 5)
intWrapper1.sadProperty = 5
val intWrapper2 = IntWrapper(actualInt = 10)
intWrapper2.sadProperty = 5

打印,

E/AreTheyEqual?: false

因为生成的equals验证生成的组件(actualInt(与两个CCD_。

现在转到Jetpack Compose,应用我们对数据类、所了解的一切

  • 第一个test符合data class的所有内容,它创建了一个具有新值的新对象,而这正是Compose触发re-composition所需要的。

  • 第二个test不会触发re-compositionCompose仍然看到相同的IntWrapper实例,因为sadProperty不是将由数据类的等于运算使用的生成组件的一部分。

在Compose中,必须使用以下两种方法之一才能成功执行重组操作:

1-使用mutableStateListOf((,但是,通过更新列表中项目的值,可以执行重新组合操作

2-使用你自己的方法,你张贴

但对于第二种方法,您需要告诉Compose actualInt已经更改,因此您需要创建一个int的新实例。

如果你不想这样做,你需要更多地解释你的场景,这样我就可以提供一个更完整的指南

最新更新