RecyclerView 缓存原理
通常认为RecyclerView有四级缓存,RecyclerView的缓存是通过Recycler类来完成的,方法的入口:
public View getViewForPosition(int position) {
return getViewForPosition(position, false);
}
缓存的内容是ViewHolder,缓存的地方,是Recycler的几个list:
final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<ViewHolder>();
private ArrayList<ViewHolder> mChangedScrap = null;
final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
private final List<ViewHolder>
mUnmodifiableAttachedScrap = Collections.unmodifiableList(mAttachedScrap);
private int mViewCacheMax = DEFAULT_CACHE_SIZE;
private RecycledViewPool mRecyclerPool;
private ViewCacheExtension mViewCacheExtension;
private static final int DEFAULT_CACHE_SIZE = 2;
第一级缓存
mAttachedScrap: 用于缓存显示在屏幕上的 item 的 ViewHolder
mChangedScrap: 还是屏幕内的ViewHolder,没看懂啥意思,可能是用于缓存局部改变时候的holder
第二级缓存
mCachedViews:划出屏幕外的item,这个list的默认大小是2,
第三级缓存
mViewCacheExtension:自定义缓存,RecyclerView默认是没有实现的,留给开发者自己实现
第四级缓存
mRecyclerPool:mCachedViews的数量达到上限之后,会把ViewHolder存入mRecyclerPool。mRecyclerPool用SparseArray来缓存进入这一级的ViewHolder:
static class ScrapData {
final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
int mMaxScrap = DEFAULT_MAX_SCRAP;
long mCreateRunningAverageNs = 0;
long mBindRunningAverageNs = 0;
}
SparseArray<ScrapData> mScrap = new SparseArray<>();
但存在mRecyclerPool的 ViewHolder 的数据信息会被重置掉,相当于 ViewHolder 是一个重创新建的一样,所以需要重新调用 onBindViewHolder 来绑定数据,所以尽量不要让ViewHolder进入这一层
缓存优化
进入RecyclerPool的ViewHolder会被重置,会从新执行bindViewHolder,所以从效率上来讲,很费性能。
所以为了避免进入这一层缓存,可以在在第三层自定义缓存自己实现,也就是自定义mViewCacheExtension。在这里自己维护一个viewType对应View的SparseArray。这样可以避免因为多种type导致的holder重建。
public abstract static class ViewCacheExtension {
@Nullable
public abstract View getViewForPositionAndType(@NonNull Recycler recycler, int position,
int type);
}
注意getViewForPositionAndType返回的是view而不是ViewHolder,然后会通过view的layoutParams拿到ViewHolder。