BRVAH与ViewBinding的二次"碰撞"

1,158 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情

之前写过一篇文章基于BaseRecyclerViewAdapterHelper与ViewBinding爬坑封装之旅文章,主要是讲解基于BRVAH和ViewBinding封装适配器的:

image.png

这种封装有一个弊端,ViewBinding是需要由子类Adapter重写createViewBinding()方法传入具体创建的ViewBinding实例,写起来比较麻烦。

Koltin本身是支持函数类型的,即我们可以将方法作为参数进行传递,利用这个特性,那我们就对上面封装的适配器进行下二次封装。

1. 函数类型传递ViewBinding创建方法

我们定义一个函数类型创建ViewBinding:

val mBinding: (LayoutInflater, ViewGroup, Boolean) -> VB

ViewBinding.inflate方法本身是可以转换成我们定义的函数类型的,前提是方法参数签名和返回值类型二者要相同。

我们把这个创建ViewBinding具体实例的函数类型作为BaseBindingAdapter的构造参数定义:

abstract class BaseBindingAdapter<VB: ViewBinding, T>(val binding: (LayoutInflater, ViewGroup, Boolean) -> VB,
                                                      data: MutableList<T>? = null):
}

然后我们外部就可以这样使用:

class TestAdapter: BaseBindingAdapter<ActivityChapterBinding, String>(ActivityChapterBinding::inflate) {
    override fun convertPlus(binding: ActivityChapterBinding, item: String) {
    }
}

可以看到,我们不再需要重写方法createViewBinding()创建ViewBinding,而是直接利用方法引用ViewBinding::inflate作为构造参数进行传入,这样看起来是不是方便很多 !!

2. BRVAHsetOnItemClickListener中position参数传递的是什么

直接从BRVAH源码中寻找答案:

//设置点击事件
override fun setOnItemClickListener(listener: OnItemClickListener?) {
    this.mOnItemClickListener = listener
}

//触发mOnItemClickListener点击事件回调调用
protected open fun setOnItemClick(v: View, position: Int) {
    mOnItemClickListener?.onItemClick(this, v, position)
}

//调用setOnItemClick方法
protected open fun bindViewClickListener(viewHolder: VH, viewType: Int) {
    mOnItemClickListener?.let {
        viewHolder.itemView.setOnClickListener { v ->
            //获取position参数
            var position = viewHolder.adapterPosition
            ...省略
            setOnItemClick(v, position)
        }
    }
}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): VH {
    bindViewClickListener(viewHolder, viewType)
}

我们在setOnItemClickListener()设置的点击事件回调最终在bindViewClickListener()方法中调用。而bindViewClickListener()就是在我们熟悉的onCreateViewHolder()调用的。

我们想一下,为什么不在onBindViewHolder()方法中设置点击事件调用mOnItemClickListener呢,这样就可以直接使用onBindViewHolder()position了?

关于这个问题,从两方面来解答:

  • 回收复用ViewHolder的角度:如果ViewHolder回收到了RecycleViewPool中且需要复用,需要重新执行onBindViewHolder()重新绑定数据,但这个和点击事件设置没啥关系,为了避免重复设置所以就放到了onCreateViewHolder设置

  • position位置正确获取的角度:从源码中可以看到,传递给mOnItemClickListener回调的position参数是通过viewHolder.adapterPosition获取的,不依赖onBindViewHolder()参数的position

关于第二点,即使点击事件放到onBindViewHolder()设置也不会依赖其参数中的position,这个是为什么呢?

举个例子,如果当前存在三个Item:A、B、C,当删除A及A在的数据源集合中的数据后,如果点击事件使用的positiononBindViewHolder()参数中的,那么此时点击B中拿到的position还是1,所以就会错误的使用C的数据(因为A已经删除了,position为1对应的是C的数据);

而如果使用的是viewHolder.adapterPosition,那点击B时position可以拿到正确的位置0,点击事件才能正常按照预期效果执行

参考文章

基于BaseRecyclerViewAdapterHelper与ViewBinding爬坑封装之旅