recycleview 复用
mChangedScrap : 用来保存RecyclerView做动画时,被detach的ViewHolder。
mAttachedScrap : 用来保存RecyclerView做数据刷新(notify),被detach的ViewHolder
mCacheViews : Recycler的一级ViewHolder缓存。
RecyclerViewPool : mCacheViews集合中装满时,会放到这里。
从Recycler中获取一个ViewHolder的逻辑:
即大致步骤是:
1.如果执行了RecyclerView动画的话,尝试根据position从mChangedScrap集合中寻找一个ViewHolder
2.尝试根据position从scrap集合、hide的view集合、mCacheViews(一级缓存)中寻找一个ViewHolder
3.根据LayoutManager的position更新到对应的Adapter的position。 (这两个position在大部分情况下都是相等的,不过在子view删除或移动时可能产生不对应的情况)
4.根据Adapter position,调用Adapter.getItemViewType()来获取ViewType
根据stable id(用来表示ViewHolder的唯一,即使位置变化了)从scrap集合和mCacheViews(一级缓存)中寻找一个ViewHolder,可以用来防止刷新过程中出现的闪烁和焦点变化,参考:https://blog.csdn.net/qq_36523667/article/details/78736015、
https://cloud.tencent.com/developer/article/1146916
5.根据position和viewType尝试从用户自定义的mViewCacheExtension中获取一个ViewHolder
6.根据ViewType尝试从RecyclerViewPool中获取一个ViewHolder
7.调用mAdapter.createViewHolder()来创建一个ViewHolder
8.如果需要的话调用mAdapter.bindViewHolder来设置ViewHolder。
调整ViewHolder.itemview的布局参数为Recycler.LayoutPrams,并返回Holder
分为三种情况
1.从无到有,会create出新的view
2.整体刷新
1)存储旧的:所有的view会进入scrap状态(ViewHolder被标记为FLAG_TMP_DETACHED状态,并且其itemview的parent被设置为null),调用detachAndScrapAttachedViews把所有的view存储到mAttachedScrap中
2)获取缓存:LinearLayoutManager会当前布局子View的位置向Recycler要一个子View,即调用到tryGetViewHolderForPositionByDeadline(position..)
这个方法会尝试根据position从mAttachedScrap、hide的view集合、mCacheViews(一级缓存)中寻找一个ViewHolder,这种情况大部分是从mAttachedScrap返回复用的。
3.滚动复用
在这种情况下滚出屏幕的View会优先保存到mCacheViews, 如果mCacheViews中保存满了,就会保存到RecyclerViewPool中。
通过了解RecyclerView的四级缓存,我们可以知道,RecyclerView最多可以缓存 N(屏幕最多可显示的item数) + 2 (屏幕外的缓存) + 5*M (M代表M个ViewType,缓存池的缓存),只有RecycledViewPool找到时才会重新调用 bindViewHolder。
对比listView:
image.png1.层级不同:
RecyclerView比ListView多两级缓存,支持多个离ItemView缓存,支持开发者自定义缓存处理逻辑,支持所有RecyclerView共用同一个RecyclerViewPool(缓存池)。
具体来说: ListView(两级缓存):
2.缓存机制的不同:
mActiveViews和mAttachedScrap功能相似,意义在于快速重用屏幕上可见的列表项ItemView,而不需要重新createView和bindView;
2). mScrapView和mCachedViews + mReyclerViewPool功能相似,意义在于缓存离开屏幕的ItemView,目的是让即将进入屏幕的ItemView重用.
3). RecyclerView的优势在于a.mCacheViews的使用,可以做到屏幕外的列表项ItemView进入屏幕内时也无须bindView快速重用;b.mRecyclerPool可以供多个RecyclerView共同使用,在特定场景下,如viewpaper+多个列表页下有优势.客观来说,RecyclerView在特定场景下对ListView的缓存机制做了补强和完善。
refer:
https://juejin.im/post/5c1369cff265da613b6fa87f#heading-2
https://zhooker.github.io/2017/08/14/%E5%85%B3%E4%BA%8ERecyclerview%E7%9A%84%E7%BC%93%E5%AD%98%E6%9C%BA%E5%88%B6%E7%9A%84%E7%90%86%E8%A7%A3/
https://www.jianshu.com/p/193fb966e954