【发布时间】:2022-06-13 15:51:35
【问题描述】:
我了解到 Compose 以如下方式记住状态:
var text by remember { mutableStateOf("") }
所以在这种情况下,它会记住一个字符串的 MutableState。我的问题是为什么它要记住一个叫做“MutableState”的东西而不仅仅是字符串本身,为什么它需要一个额外的层?
【问题讨论】:
我了解到 Compose 以如下方式记住状态:
var text by remember { mutableStateOf("") }
所以在这种情况下,它会记住一个字符串的 MutableState。我的问题是为什么它要记住一个叫做“MutableState”的东西而不仅仅是字符串本身,为什么它需要一个额外的层?
【问题讨论】:
remember 用于存储对象以在发生重组时拥有它。可变状态用于触发重组,您可以查看this answer了解更多详情。
by 是 delegation,这是 Kotlin 的一个功能,可以翻译代码
var text = remember { mutableStateOf("") }
text.value = "newString"
您基本上将触发器和值存储在记忆中。当您更改 MutableState.value 时,会发生新的重组,在这个新的重组中,您将获得 MutableState 的最新值。
当其他东西触发重组(例如画布触摸位置)时,也有不需要 MutableState 的记住用例,例如 Paint 或 自定义对象。
你记得对象,因为你不会实例化它。
val paint = remember {Paint()}
var offset by remember {mutableStateOf(Offset.Zero)
然后当偏移量随着用户触摸屏发生变化时,您会触发重组,但因为您不需要再次实例化 Paint 对象。
remember only 和 remember with MutableState 有不同的用例。
【讨论】:
需要可变状态有两个原因:
remember 将保存 lambda 计算的结果,但如果您稍后更改变量 - remember 无法保存和跟踪它。解决方案是拥有一个状态持有者 - 由mutableStateOf 创建、由remember 保存的对象将始终相同,但您可以更改它的属性,在本例中为value(当您'重新使用by 的委托)。remember 保存它并更新一个属性,Compose 不会知道它已更改,并且需要更新它的视图 - 这就是创建特殊 Compose State 的原因,它通知视图它需要重新组合。您可以通过 Compose documentation 和 Thinking in Compose 中的状态继续加深您的知识。
【讨论】:
我知道已经很晚了,我会尝试与remember分享我学到的东西。
我有一个迷你待办事项应用程序,我在其中使用jetpack compose 练习我的学习,使用viewwmodel 提升的待办事项列表使用SnapshotStatelist,此列表由LazyColumn 呈现,其中每个待办事项model有它自己的rememberedstate,在那里我做了一些非常基本的 UI 功能(例如卡片提升、某些图标的可见性),我对 todo 所做的任何更改都应该传播回mutableStateList,例如当 todo 是deleted,从列表中删除,SnapshotStateList 然后会自动通知LazyColumn 执行recomposition,但是当我edit 一个Todo 时(比如,修改标题作为基本todo 功能的一部分),我还必须更新保存此待办事项的itemcomposable(一些UI更改),然后我被困住了,因为我无法弄清楚为什么itemcomposable不是recomposing,即使我能够使用以下代码验证 SnapShotStateList 项目是否已修改
val todoList = viewModel.todos
val snapshot = Snapshot.takeMutableSnapshot()
snapshot.enter {
for (todo in todoList) {
Log.e("TodoModel", todo.title)
}
}
我验证了我对 todo 所做的任何 修改 都会反映到它的主机列表中,但是呈现 todo 的 item composable 不会触发重新组合。继续阅读一些帖子并仔细思考对象引用,我认为一定有一些东西保持item 的先前状态并且更改不适用于remember,直到我发现您可以提供key到remember,它将决定remember 是否需要重新计算。现在我发现remember 只记得 initial composition 上的一个状态(状态我不是指组合状态,而是一般的状态),它将保持该初始结构/状态只要由于它所属的整个可组合组件仍在运行,在这种情况下一直到父 composable(即我的 DashboardScreen),是我提供了我的 remember re-calculate带有 todo 对象本身的键
val itemState: ItemCardState = remember(key1 = todoModel) {
ItemCardState(todoModel = todoModel)
}
这样,当SnapShotStateList 发生更改时,每个item 的remember 将看到相同的对象引用(数据类),但应用了更改。 remember 缓存初始状态并将永久保存,除非您提供一个您认为可能会更改的密钥,并让 remember 重新计算一个新的 initial 状态以被记住。
现在有了这种理解,我无法想象没有层可以容纳对象 (remember) 并在对象状态发生变化时防止不必要的重新组合。
只是分享我学到的东西,也可以讨论我可能以错误的方式说的。
【讨论】: