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

DiffUtil添加的ListListener仅首次触发,如何实现每次列表更新都收到通知

问题原因及解决办法

AsyncListDiffer的监听仅触发一次90%以上的场景都是提交列表时复用了同一个列表内存实例导致的。AsyncListDiffer内部首先会判断新旧列表的引用是否完全相同,如果相同就会直接跳过Diff计算流程,自然不会触发列表更新回调。

排查&解决方法

  • 修正列表提交逻辑,每次提交都传入新的列表副本
    不要直接修改已提交过的MutableList再提交原实例,需要基于原有列表生成新的副本后修改,再提交新实例:
    // 错误写法:复用原有列表实例
    val oldList = differ.currentList as MutableList<PlantItem>
    oldList.add(newPlantItem)
    differ.submitList(oldList) // 新旧列表引用相同,不触发Diff计算
    
    // 正确写法:生成新的列表副本提交
    val newList = differ.currentList.toMutableList()
    newList.add(newPlantItem)
    differ.submitList(newList) // 传入新实例,正常触发Diff和回调
    
  • 排查areContentsTheSame实现逻辑
    确认PlantItem类重写了equals()方法,如果是Kotlin数据类会默认生成equals逻辑,无需额外处理;如果是普通Java类,需要确保equals方法能正确比对所有业务字段的变更,否则如果两次数据内容实际不同但equals返回true,也会跳过更新回调。
  • 避免连续快速提交相同列表
    如果短时间内多次调用submitList,中间还未完成Diff计算的提交任务会被丢弃,只有最后一次提交的有效变更会触发回调。

完整验证示例

// 确认PlantItem为Kotlin数据类,默认实现equals、hashcode逻辑
data class PlantItem(val id: Int, val name: String)

val differCallback=object : DiffUtil.ItemCallback<PlantItem>(){
    override fun areItemsTheSame(oldItem: PlantItem, newItem: PlantItem): Boolean {
        return oldItem.id == newItem.id
    }
    override fun areContentsTheSame(oldItem: PlantItem, newItem: PlantItem): Boolean {
        return oldItem == newItem
    }
}
val differ = AsyncListDiffer(this,differCallback)

differ.addListListener { previousList, currentList ->
    Log.i(TAG,"list Size "+currentList.size)
}

// 第一次提交
val firstList = List(20) { PlantItem(it, "植物$it") }
differ.submitList(firstList) // 触发回调,打印size 20

// 第二次提交新实例
val secondList = firstList.toMutableList().apply {
    add(PlantItem(20, "新植物"))
}
differ.submitList(secondList) // 正常触发回调,打印size 21

内容的提问来源于stack exchange,提问作者M.ghorbani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 04:06:03