RecyclerView的回收复用策略

问题梳理

  1. 什么时候回收? 什么时候复用?(when)
  2. 回收什么? 复用什么?(what)
  3. 回收到哪里去? 复用从哪里拿? (where)
  4. 回收和复用具体策略是什么?(how)

when

RecyclerView是一个支持滑动的容器, 因此其内部的View会消失和展示. 这个过程是在滑动的状态下才会发生. 所以, **回收和复用, 都是在RecyclerView的onTouchEvent中的move事件中发生的.**具体来说, 回收发生在View从可见变不可见时, 复用发生在View从不可见变可见时.
fill方法是回收和复用的入口

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;

观察其成员, 我们可以知道:

  1. Recycler回收和复用的对象是ViewHolder(缓存类型都是ViewHolder的ArrayList),而不是View
  2. 其有四种缓存
模块 描述 场景
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数)

参考资料
时序图来源
缓存详解1
缓存详解2

猜你喜欢

转载自blog.csdn.net/Reven_L/article/details/120311066