【发布时间】:2019-08-16 07:18:05
【问题描述】:
在 ViewModel 中,我有一个 MutableLiveData,其泛型类型是自定义对象的列表。该对象有一个 selected 字段,可以从 UI 更改。现在,我使用 RecyclerView 来填充 UI,并使用 DiffUtil.Callback 来调度正确的更改。
选中“查看”的复选框时,片段中的回调(包含recyclerview)获取通知。然后调用 ViewHolder 中的一个方法来更改 item 的selected 值,然后调用setValue。
片段
private fun observeViewModel() {
viewModel.data.observe(viewLifecycleOwner, Observer {
adapter.updateItems(items)
this.items = items
})
}
override fun onSelectionChange(position: Int) {
viewModel.reverseSelection(position)
}
视图模型
fun reverseSelection(index: Int) {
data.value?.let {
if (it.size > index) {
it[index].selected = !it[index].selected
data.value = it
}
}
}
RecyclerView 适配器
fun updateItems(items: List<T>) {
val diffCallback = BaseDiffCallback(this.items, items)
val diffResult = DiffUtil.calculateDiff(diffCallback, false)
this.items = items
diffResult.dispatchUpdatesTo(this)
}
问题在于 DiffUtil 没有检测到任何更改,因为它显示片段中的 items 字段和 ViewHolder 中的数据值指向内存中的同一对象。通过日志语句,我注意到在对 ViewHolder 中的数据显式调用 setValue 之前以及在触发观察者之前,片段中的项目已经反映了更改。
请问,在我在 ViewHolder 中调用 setValue 之前,我如何才能更改 selection 状态而不让 Fragment 中的项目反映该状态?
编辑
我非常感谢那些花时间为我的问题提供解决方案的好心用户。但是,由于我没有很好地解释我的问题,因此建议的解决方案对我不起作用。
我错过的一个关键细节是我正在使用数据绑定,并且模型的检查状态决定了ViewHolder 中其他视图的状态。另外,我之前打错了,reverseSelection 不在ViewHolder 中,而是ViewModel。最后,我将Adapter 和ViewHolder 用于其他数据模型。
因此,selected 变量驻留在数据类中非常重要,否则,在查看 HashMap 或 Set 中的元素时会产生性能开销;检查position 处的项目是否被选中。数据集可能非常大。另外,因为我在其他数据模型中使用RecyclerView.Adapter和ViewHolder,所以我觉得使用HashMap或Set并不是最好的解决方案。
现在,我不再依赖 ViewHolder 来处理更改的数据模型的传播。因此,新的更新是:
视图模型
fun reverseSelection(index: Int): Boolean {
return data.value?.let {
if (it.size > index) {
it[index].selected = !it[index].selected
true
} else false
} ?: false
}
片段
override fun onSelectionChange(position: Int) {
if (viewModel.reverseSelection(position)) {
adapter.notifyItemChanged(position, 0)
}
}
我不知道这是否是最好的解决方案,但我会暂时使用它。
【问题讨论】:
标签: android kotlin viewmodel android-livedata