[Android,ViewPager]手动实现DiffAdapter

124 阅读1分钟

本人所有文章禁止任何形式的转载,谢谢

介绍

我最早接触Diff 是在Paging 中,这个相当有用,现在我们假设一个简单的场景,当户点击按钮时,在列表的最后一个添加一个元素,很显然,我们执行notifyItemInserted 就好了,并不需要使用notifyDataSetChanged。 但总会有复杂场景的,比如数据源是从外部导入,我们就只能对比新旧的数据判断哪里的是新加入的,哪里的是删除的,哪里的是移动的,就像git diff 似的。 不过好消息是谷歌已经提供了AsyncListDiffer。虽然我们一般都是和RecycleView 一起使用,但是谷歌还是抽象出一个ListUpdateCallback,然后通过AdapterListUpdateCallback 适配器适配RecycleView

实践

我们在这里实现一个使用于ViewPager 的DiffAdapter,因为一般的情况谷歌都已经提过过了,但是唯独ViewPager 没有。

AsyncListDiffer 接收一个ListUpdateCallbackDiffUtil.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)
    }

}

结束。