android 更改列表项类中的属性值时,Jetpack组合mutableStateOf列表不会触发重新组合

whhtz7ly  于 2022-12-02  发布在  Android
关注(0)|答案(2)|浏览(275)

我想我在这里遗漏了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)})
        }
    }

}

Works:(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)})
        }
    }

}

有人能解释一下为什么会这样吗?

y53ybaqx

y53ybaqx1#

这看起来像是一个既有Jetpack Compose又有关于Kotlin数据类的问题,跟我说说,我会尽力的。
让我们先从Kotlin的数据类开始
kotlin docsData Class
编译器会自动从主要建构函式中宣告的所有属性衍生下列成员:

  • equals()/hashCode()配对
  • 格式为“用户(姓名=John,年龄=42)”的toString()
  • componentN()函数,这些函数按照属性的声明顺序与属性相对应。
  • 复制()。

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

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

我们可以说,IntWrapper数据类

  • 1个组件(actualInt
  • 格式为IntWrapper(actualInt=?)的toString()
  • 生成的copy()函数
  • 生成的equals()/hashCode()对

并且再次基于docs
编译器只使用在自动生成的函数的主构造函数中定义的属性。要从生成的实现中排除属性,请在类体中声明它:
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)与两个IntWrapper示例不相同。
现在转到Jetpack Compose,应用我们对数据类所了解的一切,

  • 第一个test符合关于data class的一切,它创建了一个带有新值的新对象,这就是Compose触发re-composition所需要的。
  • 第二个test将不会触发re-compositionCompose仍会看到相同的IntWrapper示例,因为sadProperty不是数据类的equals操作将使用的生成组件的一部分。
wooyq4lh

wooyq4lh2#

在构成中,您必须使用下列两种方法之一来成功执行重组作业:
1 -使用mutableStateListOf(),但是,通过更新列表中项的值,执行重组操作
2-用你自己的方法
但是对于第二个方法,您需要告诉Compose actualInt已经更改,因此您需要创建一个新的int示例。
如果您不想这样做,则需要详细说明您的方案,以便我可以提供更完整的指南

相关问题