一、RecycleView的四级缓存
1.第一级缓存mChangedScrap(ArrayList<ViewHolder>)和mAttachedScrap (ArrayList<ViewHolder>),主要用于缓存屏幕内的ViewHolder,在用户调用notifyxxx()的时候,直接取数据刷新页面。mChangedScrap和mAttachedScrap 的区别是当调用不同的notifyxxx()方法刷新页面的时候,缓存数据有些放在mChangedScrap,有些放在mAttachedScrap 。
2.第二级缓存mCachedViews (ArrayList<ViewHolder>),主要缓存刚刚滑动离开屏幕的ViewHolder,
mCachedViews 的size默认是2,当缓存数据充满时,会按先进先出(FIFO)原则,将之前先进来的ViewHolder移动到下一级缓存,然后再把新数据放入到mCachedViews 。mCachedViews 取缓存数据的方式是,按用户滑动的方式(向上、向下…),再根据当前屏幕中最上面或者最下面ViewHolder的position计算要取的ViewHolder的position,再根据计算出的position取出缓存数据。
3.第三级缓存mViewCacheExtension(ViewCacheExtension),主要是用户自定义的缓存,复写getViewForPositionAndType( Recycler recycler, int position, int type)方法实现自己的缓存策略。
4.第四级缓存mRecyclerPool(RecycledViewPool),这个看源码比较好理解。
public static class RecycledViewPool {
private static final int DEFAULT_MAX_SCRAP = 5;
static class ScrapData {
ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP;
long mCreateRunningAverageNs = 0;
long mBindRunningAverageNs = 0;
}
SparseArray<ScrapData> mScrap = new SparseArray<>();
private int mAttachCount = 0;
...
public ViewHolder getRecycledView(int viewType) {
final ScrapData scrapData = mScrap.get(viewType);
if (scrapData != null && !scrapData.mScrapHeap.isEmpty()) {
final ArrayList<ViewHolder> scrapHeap = scrapData.mScrapHeap;
return scrapHeap.remove(scrapHeap.size() - 1);
}
return null;
}
......
}
首先最外层的数据结构是SparseArray,SparseArray是<key,value>类型的数据存储结构。key是viewType,value是ScrapData,也就时根据viewType进行缓存的,这里的缓存大小应该是不受限制的。在我们开发中如果想在同一个RecycleView 中显示不同布局的ViewHolder,就可以用这个viewType实现。再看看ScrapData的结构,ScrapData中关键的mScrapHeap(ArrayList<ViewHolder>),这个缓存ViewHolder的,而且他有默认缓存大小5。这里还需要关注下这行代码
return scrapHeap.remove(scrapHeap.size() - 1);
这里取缓存数据不是get,而是remove,理解应该是显示在屏幕上的数据就应该从缓存中移除了,从屏幕上移除的数据,再缓存起来。
通过第四级缓存拿到的ViewHolder,会调用holder.resetInternal()重置,也就是拿到的是一个全新的ViewHolder,后续会调用onBindViewHolder()。
现在用下面流程图整体感受下RecycleView 的缓存机制