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

Android DiffUtil未正确触发notify致RecyclerView全量刷新问题

问题根源

问题出在DiffUtil.ItemCallback的条目匹配逻辑和Room的数据返回特性不匹配:

  • 你当前areItemsTheSame方法使用===做引用相等判断,只有两个对象指向同一内存地址时才会被识别为同一条目
  • Room在数据变更后返回的LiveData会发射全新构造的列表,列表内的所有实体类对象都是新实例,和旧列表中的对象不存在内存地址复用
  • 这种场景下所有新旧条目的areItemsTheSame判断都会返回false,DiffUtil会判定旧列表全量删除、新列表全量新增,最终触发整个RecyclerView重载,不会执行局部插入/删除的刷新逻辑。

另外需要确认:你的Mark实体必须是Kotlin data class(或正确重写了equals方法),否则areContentsTheSame中的==判断也会失效。

修复步骤
  1. 修改MarksComparator的areItemsTheSame实现,使用实体的唯一主键(即你在Mark类中用@PrimaryKey标注的字段,通常是id)判断是否为同一条目,禁止使用引用相等判断:
class MarksComparator : DiffUtil.ItemCallback<Mark>() {
    override fun areItemsTheSame(oldItem: Mark, newItem: Mark): Boolean {
        // 替换成你自己Mark实体的主键字段名
        return oldItem.id == newItem.id
    }

    override fun areContentsTheSame(oldItem: Mark, newItem: Mark): Boolean {
        return oldItem == newItem
    }
}
  1. 校验Mark实体定义,确保是data class,主键字段不可变:
@Entity
data class Mark(
    @PrimaryKey(autoGenerate = true) val id: Int = 0,
    // 替换为你实际的业务字段
    val title: String,
    val createTime: Long
)
  1. 提交列表时不要额外做修改或拷贝,直接将Room返回的列表传入submitList即可,ListAdapter内部会自动持有旧列表引用做差异计算。

修改完成后,新增/删除条目时DiffUtil会正确计算差异,调用对应notifyItem*方法执行局部刷新,不会再触发全列表重载。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 11:45:31