如图效果,通过RecyclerView实现,每次通过对每个Item前后数据进行对比来确定执行什么操作(如Item的insert、update、delete等),这里使用RecyclerView库中的DiffUtil.Callback()来进行的前后数据对比,如下示例:
class DataDiffUtil(private val oldModels: List<Any>, private val newModels: List<Any>) :DiffUtil.Callback() { /** * 旧数据 */ override fun getOldListSize(): Int = oldModels.size /** * 新数据 */ override fun getNewListSize(): Int = newModels.size // 堆代码 duidaima.com /** * DiffUtil调用来决定两个对象是否代表相同的Item。true表示两个Item相同(表示View可以复用),false表示不相同(View不可以复用) * 例如,如果你的项目有唯一的id,这个方法应该检查它们的id是否相等。 */ override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldModels[oldItemPosition]::class.java == newModels[newItemPosition]::class.java } /** * 比较两个Item是否有相同的内容(用于判断Item的内容是否发生了改变), * 该方法只有当areItemsTheSame (int, int)返回true时才会被调用。 */ override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { return oldModels[oldItemPosition] == newModels[newItemPosition] } /** * 该方法执行时机:areItemsTheSame(int, int)返回true 并且 areContentsTheSame(int, int)返回false * 该方法返回Item中的变化数据,用于只更新Item中变化数据对应的UI */ override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? { return super.getChangePayload(oldItemPosition, newItemPosition) } }以顶部的Item1 模块举例,当服务端有新数据来时,通过下面方式进行更新:
/** * use[DiffUtil] 增量更新数据 * @param newList 新数据 */ fun submitList(newList: MutableList<Any>) { //传入新旧数据进行比对 val diffUtil = DataDiffUtil(mModels, newList) //经过比对得到差异结果 val diffResult = DiffUtil.calculateDiff(diffUtil) //NOTE:注意这里要重新设置Adapter中的数据 setModels(newList) //将数据传给adapter,最终通过adapter.notifyItemXXX更新数据 diffResult.dispatchUpdatesTo(this) }
如果Item1前后数据是一样的,那么DiffUtil.Callback#areContentsTheSame() 中的oldModels[oldItemPosition] == newModels[newItemPosition] 理论上返回的就是true,Item1 模块也不会执行刷新操作了。实际跑起来能按我们的预期走吗?
public class VP2Model implements Serializable { public int id; public String content; }
看上去一切都是OK的,但是运行之后发现出问题了,即使前后数据完全一样,仍然会进行Item1的刷新,说明DiffUtil.Callback#areContentsTheSame()里的数据对比返回的是false,通过断点发现确实返回了false。
@Override public boolean equals(@Nullable Object obj) { return super.equals(obj); }Java Model 类默认的equals()方法是比较的对象内存地址,刷新前后生成的显然不是同一个对象,那么前后地址对比返回的肯定是false了,问题就出在了这里!如果我们使用 Kotlin 语言编写 Model 类就不会有这个问题,因为 Kotlin 编译器自动帮我们重写了equals()/hashCode()方法,如:
data class VP2Model( val id: Int = 0, val content: String = "", )
注意这里要用data class开头才行,上述代码转换成Java后:
可以看到 Kotlin 编写的 Model 类自动帮我们实现了其中的equals()/hashCode()方法。