BRVAH对RecycleView适配器做了哪些优化操作1

456 阅读2分钟

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

本篇文章主要是分析BaseRecyclerViewAdapterHelper内部是如何实现RecycleView的适配器的以及做了哪些优化操作。源码分析是基于BaseRecyclerViewAdapterHelper以下版本:

implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.0'

其中BaseRecyclerViewAdapterHelper简称为BRVAH

RecycleViewView点击事件设置

先说结论,RecycleView子View点击事件是在onCreateViewHolder中进行设置的,简单看下源码:

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

image.png

onCreateViewHolder调用了bindViewClickListener,并在该方法中设置了子View的点击事件和长点击事件。

为什么不再onBindViewHolder中设置而是要在onCreateViewHolder中设置点击事件呢?

因为在RecycleView列表显示的过程中,由于其回收复用机制,同一个ViewHolder可能会触发多次onBindViewHolder的执行(主要是用来重新绑定数据的),而点击事件的设置本身只用设置一次就行,所以就放在了onCreateViewHolder中设置。

ViewHolderItemView的子控件View获取

比如我们要设置一个子控件TextView的显示文本:

image.png

image.png

核心逻辑就在fun <T : View> getViewOrNull这个方法中:

open fun <T : View> getViewOrNull(@IdRes viewId: Int): T? {
    val view = views.get(viewId)
    if (view == null) {
        itemView.findViewById<T>(viewId)?.let {
            views.put(viewId, it)
            return it
        }
    }
    return view as? T
}

views是一个SparseArray<View>类型集合。

getViewOrNull()方法中,首先先从views中判断是否存在该viewId,不存在再去调用findViewById去获取,然后存入到views集合中。

这样ViewHolder发生复用onBindViewHolder多次调用重新绑定数据时,就不用每次都要重新去findViewById获取View了,而且SparseArray内部是个二分查找的实现,获取View的效率更高。

题外话:ItemView中子控件点击事件设置无效的BUG

BRVAH3.0.0的版本存在一个BUG:在onBindViewHolder中通过addChildClickViewIds()添加ItemView的子控件的点击事件,点击第一个Item无效,其他的正常,详情可见github issue列表中两条数据添加监听...

想要解决这个问题,可以在基于BaseQuickAdapter自定义的Adapter构造方法中添加:

class CustomAdapter: BaseQuickAdapter<String, BaseViewHolder>() {
    init {
        addChildClickViewIds()
    }
}