无唯一标识符条目如何正确实现ListAdapter的areItemsTheSame方法?
无唯一标识的DiffUtil.ItemCallback实现方案
无唯一ID的data class如何实现areItemsTheSame
分场景适配:
- 如果列表仅会更新现有条目的内容,不会发生增删、移动条目的操作,可直接用位置作为判断依据,
areItemsTheSame中返回oldItemPosition == newItemPosition即可。 - 如果列表存在增删、移动场景,最稳妥的方案是手动给data class新增唯一标识字段,可以是业务侧的唯一ID,也可以是多个不会发生变更的字段组合成的唯一键,甚至是初始化时生成的UUID,保证每个条目有全局唯一的识别标识。
双方法都写oldItem == newItem导致闪烁的原因
DiffUtil的两层判断分工明确:areItemsTheSame用于判断两个对象是否对应列表的同一个条目,areContentsTheSame仅在前者返回true时才会调用,用于判断同一个条目的内容是否发生变更。
如果两层都直接判断对象相等,只要条目内容发生变化,areItemsTheSame就会返回false,DiffUtil会判定为旧条目被删除、新条目被插入,自然会触发整条的删除+插入动画,也就是你观察到的全条闪烁。
仅判断数据类型一致就返回true的可行性
该方案仅在「单类型条目且列表中同类型条目仅存在一个」「列表永远不会触发增删、移动操作」的极端场景下可用,绝大多数业务场景不建议使用,核心原因如下:
- 如果列表内存在多个同类型的条目,
areItemsTheSame全返回true会导致DiffUtil判定所有条目为同一个,后续增删、移动条目时的差分计算完全错误,会出现显示错乱、动画异常等不可预期的问题。 - 你当前使用没有问题,只是刚好适配了上述极端场景,只要后续列表逻辑调整,支持增删移动或者多同类型条目,就会触发异常。
临时规避闪烁的过渡方案
如果暂时无法给data class新增唯一标识,可在areItemsTheSame中用多个不会随内容更新变更的字段做组合判断,比如用户条目的昵称+注册时间组合,只要组合值不变就判定为同一个条目,即可避免全条闪烁的问题,同时不会影响正常的内容更新识别。
内容的提问来源于stack exchange,提问作者Stylianos Gakis
相关产品推荐
相关产品推荐

