本人所有文章禁止任何形式的转载,谢谢
介绍
我最早接触Diff 是在Paging 中,这个相当有用,现在我们假设一个简单的场景,当户点击按钮时,在列表的最后一个添加一个元素,很显然,我们执行notifyItemInserted 就好了,并不需要使用notifyDataSetChanged。
但总会有复杂场景的,比如数据源是从外部导入,我们就只能对比新旧的数据判断哪里的是新加入的,哪里的是删除的,哪里的是移动的,就像git diff 似的。
不过好消息是谷歌已经提供了AsyncListDiffer。虽然我们一般都是和RecycleView 一起使用,但是谷歌还是抽象出一个ListUpdateCallback,然后通过AdapterListUpdateCallback 适配器适配RecycleView。
实践
我们在这里实现一个使用于ViewPager 的DiffAdapter,因为一般的情况谷歌都已经提过过了,但是唯独ViewPager 没有。
AsyncListDiffer 接收一个ListUpdateCallback 和DiffUtil.ItemCallback<T>。
我们先构造后者。
private val diff = object : DiffUtil.ItemCallback<TabItem>() {
override fun areItemsTheSame(oldItem: TabItem, newItem: TabItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: TabItem, newItem: TabItem): Boolean {
return oldItem.data == newItem.data
}
}
在回掉areContentsTheSame 前就能够确定areItemsTheSame 返回了true,所以我们不需要再次比较id。
然后我们把ItemCallback 和adapter 一起传递给AsyncListDiffer。
private val asyncListDiffer = AsyncListDiffer(adapter, diff)
当我们获取最新的数据后通过submitList 传递数据给asyncListDiffer。为了更好的使用我们最后把这些组合成一个新的Adapter。
class DiffAdapter(
childFragmentManager: FragmentManager,
viewLifecycleOwner: LifecycleOwner
) : FragmentStateAdapter(childFragmentManager, viewLifecycleOwner.lifecycle) {
private val diff = object : DiffUtil.ItemCallback<TabItem>() {
override fun areItemsTheSame(oldItem: TabItem, newItem: TabItem): Boolean {
return oldItem.id == newItem.id
}
override fun areContentsTheSame(oldItem: TabItem, newItem: TabItem): Boolean {
return oldItem.id == newItem.id
}
}
private val asyncListDiffer = AsyncListDiffer(this, diff)
override fun getItemCount() = asyncListDiffer.currentList.size
override fun createFragment(position: Int) =
TabFragment.create(asyncListDiffer.currentList[position].id!!)
fun submitList(it: List<TabItem>) {
asyncListDiffer.submitList(it)
}
}
结束。