问题梳理
- 什么时候回收? 什么时候复用?(when)
- 回收什么? 复用什么?(what)
- 回收到哪里去? 复用从哪里拿? (where)
- 回收和复用具体策略是什么?(how)
when
RecyclerView是一个支持滑动的容器, 因此其内部的View会消失和展示. 这个过程是在滑动的状态下才会发生. 所以, **回收和复用, 都是在RecyclerView的onTouchEvent中的move事件中发生的.**具体来说, 回收发生在View从可见变不可见时, 复用发生在View从不可见变可见时.
what & where
RecyclerView中回收复用是通过其内部类Recycler实现的.(点此查看源码 )
public final class Recycler {
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
ArrayList<ViewHolder> mChangedScrap = null;
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
private final List<ViewHolder>
mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
private int mRequestedCacheMax = DEFAULT_CACHE_SIZE;
int mViewCacheMax = DEFAULT_CACHE_SIZE;
RecycledViewPool mRecyclerPool;
private ViewCacheExtension mViewCacheExtension;
static final int DEFAULT_CACHE_SIZE = 2;
观察其成员, 我们可以知道:
- Recycler回收和复用的对象是
ViewHolder
(缓存类型都是ViewHolder的ArrayList),而不是View
- 其有四种缓存
模块 | 描述 | 场景 |
mAttachedScrap | 存储被标记移除但有可能被复用的ViewHolder(如滑出去一半的View) | 隐藏一整个RecyclerView, 则其中所有的item都会存在mAttachedScrap |
mChangedScrap | 存储数据已经改变, 需要更新的ViewHolder | notifyItemChanged(index),如果当前index显示在屏幕中,这个index的ViewHodler会被存储到mChangedScrap中。 |
mCachedViews | 用于缓存滑出屏幕的ViewHodler。 | 一个被完全移出屏幕的ViewHolder的有限队列, 当其满了并加入新的时, 会先把最老的移入mRecyclerPool中 |
mViewCacheExtension | 给开发者自定义View缓存的一个帮助类,需要自己定义View的缓存与回收逻辑。 | 不常用。 |
mRecyclerPool | 同一个Adapter下, RecycledViewPool能够共享多个RecyclerView之间的View。默认情况下每个RecyclerView会自己创建一个; 可以通过setRecycledViewPool()手动设置。 | mCachedViews中放满的情况下会放到RecycledViewPool中 |
注:
- 与当前的RecyclerView一一对应:mAttachedScrap、mChangedScrap、mCachedViews
- 可能多个RecyclerView共享:mViewCacheExtension、mRecyclerPool
How
回收
过程(源码 ):
复用
过程(源码 ):
缓存获取顺序:
- **只有从RecycledViewPool才会执行bindViewHolder(). 从其他缓存获取到ViewHolder直接返回. **
- 当四级缓存都获取不到时, 才会createViewHolder()
mCachedViews
- 可以通过setItemViewCacheSize()设定其大小.
- 默认为2.
RecycledViewPool
- 其按照ViewType来查找ViewHolder
- 每个ViewYype默认最多存储5个
- 返回的ViewHolder需要重新执行bindViewHolder()来更新内容
缓存数
默认下, RecyclerView可以存储:
N(屏幕最多可显示的Item数) + 2(mCachedViews大小) + 5*M(ViewType数)