我在 Jetpack Compose 中有一个代表汽车的数据类:
data class Car(
val id: Int = 0,
val brand: String = "",
val model: String = "",
val year: Int = 2020
)
在我的可组合项中,我根据 TextField 组件中的用户输入更新此数据类的品牌和模型属性。目前,每次用户输入内容时,我都会使用 copy() 函数,如下所示:
@Composable
fun CarScreen() {
var car by remember { mutableStateOf(Car()) }
Column {
TextField(
value = car.brand,
onValueChange = { newBrand ->
car = car.copy(brand = newBrand) // Using `copy()`
},
label = { Text("Brand") }
)
TextField(
value = car.model,
onValueChange = { newModel ->
car = car.copy(model = newModel) // Using `copy()`
},
label = { Text("Model") }
)
}
}
忧虑:
我担心每次更改文本时都调用 copy() 可能会导致性能问题,因为每次用户在 TextField 中键入内容时,它都会创建一个新的 Car 对象实例。每次击键都会发生这种情况,在包含许多字段的大型应用或表单中,这可能会变得效率低下。
我的问题:
- 在 Jetpack Compose 中,对每个 TextField 调用 copy() 是否会导致性能低下?这种不断创建和重组对象的行为是否会导致明显的性能下降,尤其是在较大的数据模型或频繁输入的情况下?
- 有哪些更好的方法来处理频繁的文本输入更改,而不必一直使用 copy(),同时仍确保 Compose 可以在必要时重组 UI?我想维护一个反应式 UI,而无需过多创建对象。
如果有一种方法,我们可以直接更改数据类值而不是复制对象,并自动触发重组,那会怎样?
对于视图,建议不要实例化新对象,尤其是在
onDraw
多次调用的函数中。但是,在 Jetpack Compose 中,如果没有强跳过,则不鼓励使用具有可变参数的数据类,因为如果组合发生在具有不稳定参数的范围函数中,对于数据类的可变参数,或来自外部库的不稳定类,或项目中未扩展组合编译器的其他模块,它会触发该函数的重组。
https://developer.android.com/develop/ui/compose/performance/stability#mutable-objects
在上面的函数中,如果您使用具有可变参数的数据类,当选定的 Row 发生变化时,ContactDetails 也会发生变化,即使 Contact 没有改变,因为 ContactDetails 的输入不稳定。
而且,复制汽车等对象或具有原始值的数据或包含原始值或字符串的类不会产生明显的性能开销。您可能只需要考虑数据类是否包含大数据(例如 Bitmap 或 Base64 格式的图像),即使在这种情况下也必须进行深度复制。
但是 Kotlin 的copy函数是浅拷贝,如果你不创建新的实例,它只会复制对象的引用。
印刷
但是,如果您仍然希望通过不创建新的持有者对象来优化它,则可以使用带有 @Stable 注释的变量,而不需要强跳过,这将阻止函数的重组(如果当另一个
State
或父函数的输入的更改触发父范围内的重组时它的输入没有改变)。当你的汽车属性发生变化时触发重组,例如
使用另一个 SnapshotMutationPolicy
MutableState 的默认策略是
structuralEqualityPolicy()
检查value
您设置的新值是否==
与上一个值相同。在数据类中,equals 由主构造函数的参数决定。通过更改此策略,您可以触发重组,即使使用相同的对象,例如
正如您所看到的,通过
neverEqualPolicy()
策略,您可以通过分配相同的对象来触发重组。它适用于任何类,您可以通过将计数器值设置为相同值来触发重组。
使用具有 MutableStates 的类
这种方法在 RememberXState 类和 Google 的 Jetsnack 示例中被广泛使用。
ScrollState,jetsnack 搜索状态
您只需将您的类划分为应该触发重组的属性和不需要的其他属性,因为它们在触发重组时也会发生变化。
在 gradle 文件集中启用强跳过
因此上述更改将应用于类、lambda 和函数
请注意评论中的建议。如果您将其更改
val
为var
,则会破坏应用程序的功能,因为 Compose 无法观察到可变变量的变化。因此,当您键入时,Jetpack Compose 将不再触发重新组合,并且您将不会在 中看到任何内容
TextField
。在 Jetpack Compose 中,我认为将表单的所有值存储在单个 中是绝对常见的
data class
。您不必担心这里的性能问题,除非您真的遇到它们。