android - MutableLiveData 的变化在显式设置值之前反射(reflect)在观察者中

标签 android kotlin viewmodel android-livedata

在 ViewModel 中,我有一个 MutableLiveData,其通用类型是自定义对象列表。该对象有一个可从 UI 更改的 selected 字段。现在,我使用 RecyclerView 来填充 UI,并使用 DiffUtil.Callback 来调度正确的更改。

当 ViewHolder 中的复选框被选中时,Fragment(包含 RecyclerView)中的回调会收到通知。然后调用 ViewHolder 中的一个方法来更改项目的 selected 值,然后调用 setValue

fragment

private fun observeViewModel() {
    viewModel.data.observe(viewLifecycleOwner, Observer {
        adapter.updateItems(items)
        this.items = items
    })
}

override fun onSelectionChange(position: Int) {
    viewModel.reverseSelection(position)
}

View 模型

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 没有检测到任何变化,因为 Fragment 中的 items 字段和 ViewHolder 中的数据值似乎指向内存中的同一个对象。通过日志语句,我注意到在对 ViewHolder 中的数据显式调用 setValue 和触发观察器之前, fragment 中的项目已经反射(reflect)了更改。

请问,在调用 ViewHolder 中的 setValue 之前,如何才能更改 selection 状态而不让 Fragment 中的项目反射(reflect)状态?


编辑

我非常感谢那些花时间为我的问题提供解决方案的好心用户。但是,因为我没有很好地解释我的问题,所以建议的解决方案对我不起作用。

我错过的一个关键细节是我正在使用数据绑定(bind),并且模型的检查状态决定了 ViewHolder 中其他 View 的状态。此外,我之前打错了,reverseSelection 不在 ViewHolder 中,而是在 ViewModel 中。最后,我将 AdapterViewHolder 用于其他数据模型。

因此,selected 变量驻留在数据类中非常重要,否则在查看 HashMap 或 Set 中的元素时会产生性能开销;检查 position 的项目是否被选中。数据集可能非常大。此外,因为我正在为其他数据模型使用 RecyclerView.AdapterViewHolder,所以我觉得使用 HashMap 或 Set 并不是最佳解决方案。

现在,我不再依赖 ViewHolder 来处理已更改数据模型的传播。因此,新的更新是:

View 模型

fun reverseSelection(index: Int): Boolean {
    return data.value?.let {
        if (it.size > index) {
            it[index].selected = !it[index].selected
            true
        } else false
    } ?: false

}

fragment

override fun onSelectionChange(position: Int) {
        if (viewModel.reverseSelection(position)) {
            adapter.notifyItemChanged(position, 0)
        }
    }

我不知道这是否是最好的解决方案,但我暂时会使用它。

最佳答案

在适配器中,我会创建一个散列映射来存储所选项目的索引,而不是直接修改项目。这将确保对象未被修改,但您还存储了选定的索引。

关于android - MutableLiveData 的变化在显式设置值之前反射(reflect)在观察者中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57520398/

相关文章:

android导出到csv并作为电子邮件附件发送

Android 颜色选择器不适用于 Android 4

android - Kotlin 将对象转换为另一个对象

android - 为什么 android ndk 不能为多个平台编译?

java - 用覆盖层替换库存状态栏?

android - Dagger 2 androidx fragment 不兼容类型

foreach - Kotlin:迭代列表并在索引处添加项目

android - 在 kotlin 中如何使用 ViewModel 和 ViewModelProvider.AndroidViewModelFactory?

c# - 无法使我的 ViewModelLocator 工作

java - ViewModel 构造函数应该用@Inject 注释而不是@AssistedInject