一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第12天,点击查看活动详情。
之前写过一篇文章基于BaseRecyclerViewAdapterHelper与ViewBinding爬坑封装之旅文章,主要是讲解基于BRVAH和ViewBinding封装适配器的:
这种封装有一个弊端,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. BRVAH
的setOnItemClickListener
中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在的数据源集合中的数据后,如果点击事件使用的
position
是onBindViewHolder()
参数中的,那么此时点击B中拿到的position
还是1,所以就会错误的使用C的数据(因为A已经删除了,position为1对应的是C的数据);
而如果使用的是
viewHolder.adapterPosition
,那点击B时position
可以拿到正确的位置0,点击事件才能正常按照预期效果执行