本文以通俗的语言,记录在阅读RecyclerView源码时的一些心得🤔。
添加view的过程
- 在使用recyclerView的setAdapter方法设置adapter时,会调用RecyclerView的requestLayout()方法,进而执行measure、layout等生命方法;
- 何时添加的子view(adapter里面的一堆):在RecyclerView执行layout时,实际会调用LayoutManager的onLayoutChildren()方法去layout子view,如LinearLayoutManager,方法堆栈:onLayoutChildren()->fill()->layoutChunk()。
- 滚动时如何判断需要add一个子view:核心方法:updateLayoutState(),以向右滑动为例:①拿到当前最左边的view(getChildClosestToStart()),一般就是child0;②然后计算还可以向左滑动多远的距离才需要add一个view,getDecoratedStart()方法:计算最左边的子view在RecyclerView中的位置(getLeft()+margin)。经过计算之后可以知道:是否需要添加新的子view来填充RecyclerView。
View的复用
下面描述RecyclerView是如何对view进行复用的。
一、RecyclerView的缓存
- 一级缓存:mAttachedScrap
mAttachedScrap中的view不需要重新bindView。ScrapView主要用于对于屏幕内可见的ChildView的缓存,缓存中的ViewHolder不需要重新Bind,缓存时机是在onLayout的过程中,并且用完即清空,里面的view只是被detach,不会被remove,在onLayout时会使用; - 二级缓存:mCacheViews
mCacheViews也不需要重新bind,里面的view是被remove过的,缓存滑动时即将离开RecyclerView的ViewHolder; - 三级缓存:mViewCacheExtension
- 四级缓存:mRecyclerPool
二、view查找过程
在RecyclerView的view不足时,需要addView,view的查找过程如下,一层层降级获取可使用的view:
- 优先从mAttachedScrap列表中查找,查找的position必须和列表中某个holder的position完全一致,即:要查找的holder和该缓存里面的某个holder达到完全一致的状态;
- 从mCachedViews列表中查找,也需要position完全一致匹配。mCachedViews默认最大缓存为2,当大于该值时,将holder缓存移至RecycledViewPool;
- mAdapter.hasStableIds()为true时,否则转4:从mAttachedScrap、mCachedViews列表中查找viewType相同的holder,在1、2都失败的情况下,说明position完全匹配失败,这时候需要找到viewType相同的holder缓存;
- 从RecycledViewPool里面根据viewType查找缓存的holder。
说明:RecycledViewPool针对每一种viewType有一个缓冲池,池子大小默认为5,当某一种viewType的holder在RecycledViewPool中的缓存数量大于最大值时,会被丢弃; - 缓存全部无法命中,则调用Adapter.createViewHolder新建holder。