RecyclerView 的回收和复用
来源:互联网 发布:网络推手阿建推网红 编辑:程序博客网 时间:2024/06/05 11:12
RecyclerView 的回收和复用
前段时间在面试的时候这个问题被问到过,可惜自己在用的时候只知道 RecyclerView 可以通过回收和复用 view 来达到减少创建视图的优化。单内部是怎么缓存的?缓存多少?怎么区分不同的 View?
趁这个周清闲,把这个问题解决一下,源码之下无密码,那我们就从源码入手!
View 的回收
/*** 使用给定的回收机制删除子视图并回收*/public void removeAndRecycleView(View child, Recycler recycler) { removeView(child); recycler.recycleView(child);}
这个方法就是我们要研究的入口,这个方法很简单,第一行是删除子视图,第二行是回收器回收视图,我们跟进第二行的代码。
public void recycleView(View view) { // This public recycle method tries to make view recycle-able since layout manager // intended to recycle this view (e.g. even if it is in scrap or change cache) ViewHolder holder = getChildViewHolderInt(view); if (holder.isTmpDetached()) { removeDetachedView(view, false); } if (holder.isScrap()) { holder.unScrap(); } else if (holder.wasReturnedFromScrap()) { holder.clearReturnedFromScrapFlag(); } recycleViewHolderInternal(holder);}
这段代码主要是做了一些判断,不是我们要关注的部分,在最后一行调用了 recyclerViewHolderInternal ,我们继续跟进去。
这个方法的代码比较多,我们之截取中间一段感兴趣的代码。
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0)
int mViewCacheMax = DEFAULT_CACHE_SIZE
static final int DEFAULT_CACHE_SIZE = 2
从这里可以看到,并不是不用的 View 就会立即被回收的,而是先存储在 mCachedViews 中,当 mCachedViews 大于 2 时会回收位于第 0 个位置的视图。
/** * 回收缓存的视图,并从列表(mCachedViews)中删除 */ void recycleCachedViewAt(int cachedViewIndex) { ViewHolder viewHolder = mCachedViews.get(cachedViewIndex); addViewHolderToRecycledViewPool(viewHolder, true); mCachedViews.remove(cachedViewIndex);}
其中 * addViewHolderToRecycledViewPool * 方法中比较重要的是获得了 * RecycledViewPool * 对象,并向其中添加传入的 viewHolder。
public void putRecycledView(ViewHolder scrap) { final int viewType = scrap.getItemViewType(); final ArrayList scrapHeap = getScrapDataForType(viewType).mScrapHeap; if (mScrap.get(viewType).mMaxScrap <= scrapHeap.size()) { return; } scrap.resetInternal(); scrapHeap.add(scrap);}
这里再加上 scrap 的一些代码就非常好理解了
static class ScrapData { ArrayList<ViewHolder> mScrapHeap = new ArrayList<>(); int mMaxScrap = DEFAULT_MAX_SCRAP; long mCreateRunningAverageNs = 0; long mBindRunningAverageNs = 0;}SparseArray<ScrapData> mScrap = new SparseArray<>();
可以看到在回收 View 的时候是按 ViewType 来存储在不同的 ScrapData 中,并且最大默认缓存数是 5.
SparseArray 相当于 HashMap
View 的复用
View 的复用我们可以从 getViewForPosition 方法开始分析,重点在 tryGetViewHolderForPositionByDeadline 方法中,这个方法很长,我们截取重要的部分。
可以看到我们利用 RecycledViewPool 通过 viewType 获得缓存的 holder
/** * 返回缓存并删除 */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;}
View 的复用过程相对还是比较好理解的,就是通过 ViewType 来获得 RecycledViewPool 中缓存的视图。
其他
在这次学习的过程中还注意到,可以通过给 RecyclerView 设置 RecycledViewPool 来实现多个 RecyclerView 之间的 view 共享,感觉这个挺不错。比如一些 等待View, 错误View,但 ViewType 一定要处理好。
- RecyclerView 的回收和复用
- RecyclerView和ListView的复用BUG以及解决办法
- RecyclerView回收原理分析
- RecyclerView回收机制分析--“取”
- RecyclerView和CardView实现列表功能,用LeanCloud所存储的数据中填充RecyclerView
- ListView 和RecyclerView的比较
- RecyclerView和SwipeRefreshLayout的使用
- RecyclerView 的研究和使用
- RecyclerView的拖动和滑动
- RecyclerView的插入和删除
- RecyclerView的使用和样式
- RecyclerView和CardView的使用
- RecyclerView 和 ListView的区别
- RecyclerView和ListView的异同
- RecyclerView和ListView的异同
- RecyclerView和ListView的异同
- RecyclerView和ListView的异同
- RecyclerView的使用和封装
- Java 实现长图文生成
- VC读写剪贴板
- 子序列的和(subsequence)
- 适配器模式
- 引言之“财务管理”
- RecyclerView 的回收和复用
- Oracle 中 nvl、nvl2、nullif、coalesce、decode 函数的用法详解
- Git提交项目到GitHub配置
- 查看uboot源代码的预备知识
- JavaScript—易犯错的题目
- 关于WINDOWS去ping linux为什么ping不通
- Spark Core 调优指南
- jdbc中连接驱动的方式的区别
- Linux文件类型与扩展名