RecycleView深入学习

RecyclerView真的是宝藏View,学习记录。 

一个不太常用的属性,作用不太容易描述,可以自己测试一下。

android:clipToPadding="false"
android:paddingBottom="@dimen/x10"
val linearLayoutManager = LinearLayoutManager(this)
linearLayoutManager.orientation = LinearLayoutManager.VERTICAL
val mDivider = LinearItemDecotation(this)
val adapter = RecyclerAdapter(this, mDatas)

mRecycler.layoutManager = linearLayoutManager
mRecycler.addItemDecoration(mDivider)
mRecycler.adapter = adapter

Adapter中的主要方法:

class RecyclerAdapter(context: Context, mDatas: ArrayList<String>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    override fun onCreateViewHolder(p0: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    }

    override fun onBindViewHolder(p0: RecyclerView.ViewHolder, p1: Int) {
    }
}

onCreateViewHolder会在创建一个新View的时候调用
onBindViewHolder会在已经存在的View绑定数据时调用。
如果新创建的View,则会先调用onCreateViewHolder来创建View,然后调用onBindViewHolder来绑定数据,如果是复用的View,就会只调用onBindViewHolder。

RecyclerView回收原理

RecyclerView中用两级缓存(mCachedViews和mRecyclerPool)来保存这些已经被废弃(Removed)的HolderView。这两个缓存区别是:mCacheViews是第一级缓存,他的size是2,只能保存两个HolderView,始终保存最新被移除的HolderView。当mCachedViews满了以后,会利用先进先出原则,把老的HolderView存放到mRecyclerPool中,在mRecyclerPool中,他默认size是5。

detachAndScrapAttachedViews(recycler);的作用是将屏幕上所有的HolderView与屏幕分离,将他们从RecyclerView布局中拿下来,然后存放在一个列表中,在重新布局时,把这些HolderView重新一个个放在新位置上。将屏幕中的HolderView从RecyclerView中拿下来存放在mAttachedScrap列表中。mAttachedScrap中存储的就是重新布局前从RecyclerView中剥离出来的当前显示在屏幕中的HolderView。这些HolderView不参与回收复用,单纯只是为了先从RecyclerView中拿下来,然后再重新布局。新布局中没有用到的HolderView,会从mAttachedScrap中移到mCachedViews中,重新参与复用。

RecyclerView允许我们自己扩展回收池,并且给他预留了一个变量mViewCacheExtension,一般不会用到。

至此,在RecyclerView中,总共有四个池子:mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool。

  1. mAttachedScrap不参与回收复用,只保存重新布局时,从RecyclerView中取出的显示在当前屏幕上的hoderView列表。
  2. mCachedViews、mViewCacheExtension、mRecyclerPool总成了回收复用的三级缓存。当RecyclerView要拿一个复用的HolderView时,获取优先级是:mCachedViews>mViewCacheExtension>mREcyclerPool。一般我们不会自定义mViewCacheExtension,所以获取缓存的顺序其实为mCachedViews>mRecyclerPool。
  3. 其实mCachedViews是不参与回收复用的,他的作用就是保存最新被移除的HolderView并且是通过removeAndRecycleView(view,recycler)方法移除的。他的作用是在需要新的HolderView时,精确匹配是不是刚刚移除的,如果是,就直接返回给RecyclerView展示,如果不是,那么及时mCachedViews中有holderView实例,也不会返回,二十到mRecyclerPool中去找一个HolderView实例返回,重新绑定数据使用。
  4. 在mAttachedScrap、mCachedViews中的holderView都是精确匹配的,真正被标识为废弃的是存放在mRecyclerPool中的holderView。

需要注意的是,在mAttachedScrap和mCachedViews中拿到的holderView,因为都是精确匹配的,所以都是直接使用,不会调用onBindViewHolder重新绑定数据,只有在mRecyclerPool中拿到的HolderView才会重新绑定数据。所以只有在mCachedViews存在时,池子的使用效率是最高的,即来回滚动RecyclerView时。

当我们重写LayoutManager时,有几个函数需要注意:

  • public void detachAndScrapAttachedViews(@NonNull RecyclerView.Recycler recycler)
    仅在onLayoutChildren方法中使用,把当前屏幕上所有的HolderView与屏幕分离,存放在列表AttachedScrap中。
  • View childView = recycler.getViewForPosition(pos);
    用于向RecyclerView申请一个HolderView,至于这个holderView是从哪个池子中拿的,不需要关系,因为该方法有自己的判断 ,非常方便,正是这个函数为我们实现了复用。
  • removeAndRecycleView(child, recycler);
    仅用在滚动的时候。在滚动时,我们需要把滚出屏幕的HolderView标记为Removed,这个函数作用就是把不需要的HolderView标记为Removed。在我们标记Removed以后,就会把这个HolderView移到mCachedViews中,如果mCachedViews已满,就利用先进先出原则,将mCachedViews中老的holderView移到mREcyclerPool中,然后再把新的HolderView加入到mCachedViews中。
  • int getItemCount()
    得到的是Adapter中总共有多少数据要显示,即总的item数
  • int getChildCount() 
    得到的是当前RecyclerView在显示的item的个数,即当前屏幕中显示的item数
  • View getChildAt(int index)
    获取某个可见位置的View,即屏幕中显示的某个View。index不是Adapter中的位置索引,而是当前屏幕上的位置索引。也就是说,获取当前屏幕上显示的第一个item的View应该用getChildAt(0),如果需要获取屏幕上最后一个item的View,应该使用getChildAt(getChildCound()-1)
  • int getPosition(@NonNull View view)
    用于得到某个View在Adapter中的索引位置。拿到屏幕中显示的最后一个View在Adapter中的索引:
    View lastView = getChildAt(getChildCount() - 1);
    int pos = getPosition(lastView);

猜你喜欢

转载自blog.csdn.net/qq_34198206/article/details/84950689