You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin嵌套RecyclerView中DiffUtil失效 仅notifyDataSetChanged可刷新

嵌套RecyclerView DiffUtil失效问题解决方案

核心问题原因

  1. 复用了已提交的可变数据实例
    你在addData方法中直接修改原有Group内部的可变列表,再把同一个列表实例赋值给groupList。同时groupByData方法也复用了原有groupList实例,DiffUtil对比新旧列表时发现是同个内存地址的对象,会直接判定无变化,跳过差异计算。
  2. 列表拷贝仅为浅拷贝
    你提交列表时调用的toMutableList()仅拷贝了外层Group列表的结构,内层每个Group实例、Group内部的子列表都是原实例的引用,DiffUtil对比内容时会判定内容无变化。
  3. 多余的全量刷新调用
    你在submitList后主动调用了notifyDataSetChanged(),直接覆盖了DiffUtil的差异更新逻辑,强制全量刷新视图。
  4. 未贴出的代码大概率存在的问题:DiffUtil.ItemCallback实现错误,或者子RecyclerView的Adapter未正确提交新数据。

修复步骤

1. 所有数据类改为不可变实现

将Group、GroupKey、Abc、Qwe均定义为Kotlin数据类,内部的列表使用不可变的List而非MutableList,禁止修改已提交给Adapter的旧数据实例。

// 示例Group数据类定义
data class Group(
    val key: GroupKey,
    val list: List<Abc> // 用不可变List
)

2. 数据更新时生成全新的实例

修改addData方法,所有修改都基于新实例生成,不修改原有数据:

fun addData() {
    groupList?.let { oldList ->
        val qwe = Qwe("Vivek ${value++}", "Modi")
        val newItem = Abc(type = "Type 1", "Adding Message", qwe)
        // 生成新的外层列表实例
        val newList = ArrayDeque<Group>()
        newList.addAll(oldList)
        // 生成更新后的第一个Group实例
        val oldFirstGroup = newList.removeFirst()
        val newFirstGroup = oldFirstGroup.copy(
            list = oldFirstGroup.list + newItem
        )
        newList.addFirst(newFirstGroup)
        // 赋值新的列表实例触发更新
        groupList = newList
    }
}

3. 正确实现DiffUtil.ItemCallback

外层GroupAdapter的DiffCallback要基于内容对比,不要用引用对比:

val GROUP_DIFF_CALLBACK = object : DiffUtil.ItemCallback<Group>() {
    override fun areItemsTheSame(oldItem: Group, newItem: Group): Boolean {
        // 替换为你Group的唯一标识字段,比如GroupKey内的唯一ID
        return oldItem.key.uniqueId == newItem.key.uniqueId
    }

    override fun areContentsTheSame(oldItem: Group, newItem: Group): Boolean {
        // Kotlin数据类默认equals会对比所有字段,包括内部List的内容
        return oldItem == newItem
    }
}

子RecyclerView对应的子Adapter也要实现对应的DiffUtil.ItemCallback,外层绑定子Item时,用子Adapter的submitList提交新的子列表。

4. 删除多余的全量刷新代码

移除Observer内的notifyDataSetChanged调用:

private fun setupViewModel() {
    viewModel.groupListLiveData.observe(this) {
        if (groupAdapter == null) {
            groupAdapter = GroupAdapter(GROUP_DIFF_CALLBACK) // 传入正确的DiffCallback
            binding.recyclerview.adapter = groupAdapter
        }
        groupAdapter?.submitList(viewModel.groupList?.toList())
        // 删掉下面两行全量刷新代码
        // binding.recyclerview.post {
        //     groupAdapter?.notifyDataSetChanged()
        // }
    }
}

完成以上修改后DiffUtil即可正常计算差异,无需调用全量刷新方法即可更新嵌套RecyclerView的内容。

内容的提问来源于stack exchange,提问作者Compose Learner

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 08:36:02