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
相关产品推荐
相关产品推荐

