阅读有关jetpack compose中的副作用(在compose中思考),我找到了这个例子:
@Composable
@Deprecated("Example with bug")
fun ListWithBug(myList: List<String>) {
var items = 0
Row(horizontalArrangement = Arrangement.SpaceBetween) {
Column {
for (item in myList) {
Text("Item: $item")
items++ // Avoid! Side-effect of the column recomposing.
}
}
Text("Count: $items")
}
}
如本示例上下文中所述,这是不正确的,因为不允许修改局部变量
items
。现在我想知道什么是允许的,什么是不允许的。 compose 如何知道它可以并行评估 item in myList
?如果将 var items
移至 Column
范围内,是否允许?
更进一步,是否允许更新变量?我们可以做这样的事情吗:
class LongLastingClass() {
var someState = mutableStateOf(0)
private set
fun update(value: Int) {
someState = value
}
}
@Composable
fun ListWithUpdate(value: Int) {
val longLastingObject = remember{ LongLastingClass() }
longLastingObject.update(value)
...
}
或者是否必须将
update
移至副作用之类的地方?或者这种构造是否存在问题,因为我们最好不要修改可组合项中的状态变量,因此会产生副作用?
暂时忽略
Row
和 Column
,因为它们是内联函数并且很特殊,您永远不应该在 Compose 中编写依赖于可组合 lambda 何时执行的代码。它可能不会产生您期望的结果。
如果您将上述更改为,
@Composable
@Deprecated("Example with bug")
fun ListWithBug(myList: List<String>) {
var items = 0
A {
B {
for (item in myList) {
Text("Item: $item")
items++ // Avoid! Side-effect of the column recomposing.
}
}
Text("Count: $items")
}
}
此代码仅在调用
ListWithBug
的每一行始终调用 A
调用其 lambda 且始终调用 B
调用其 lambda 时才有效。如果调用 A
的 lambda 并跳过 B
,则当 items
执行时,0
的值将为 Text("Count: $items")
。换句话说,只有当 B
不跳过并且传递给 B
的 lambda 不跳过时,每当执行 ListWithBug
时,此代码才有效。
不需要并行性,这段代码就会出错,只是跳过。
这样就可以不使用 Compose 来计数。如果您将其更改为,
@Composable
fun WorkingList(myList: List<String>) {
A {
B {
for (item in myList) {
Text("Item: $item")
}
}
Text("Count: ${myList.size}")
}
}
它会产生相同的结果,而不依赖于何时或是否执行可组合 lambda。