RecyclerView缓存

RecyclerView分为四级缓存

RecyclerView根据不同的状态可以分为:屏幕内缓存、屏幕外缓存、自定义缓存、缓存池。RecyclerView是通过内部类Recycler来管理缓存。

   //RecyclerView子类
    public final class Recycler {     
       		 //一级缓存,屏幕内缓存
        final ArrayList<ViewHolder> mAttachedScrap = new ArrayList<>();
        ArrayList<ViewHolder> mChangedScrap = null;
			//二级缓存 屏幕外缓存
        final ArrayList<ViewHolder> mCachedViews = new ArrayList<ViewHolder>();
        ......
			//四级缓存  缓存池
        RecycledViewPool mRecyclerPool;
			//三级缓存 用户自定义
        private ViewCacheExtension mViewCacheExtension;
			//缓存默认大小
		static final int DEFAULT_CACHE_SIZE = 2;

一级缓存:屏幕内缓存(mAttachedScrap)

屏幕内缓存指在屏幕中显示的ViewHolder,这些ViewHolder会缓存在mAttachedScrap,mChangedScrap中 :
mChangedScrap 表示数据已经改变的ViewHolder列表,需要重新绑定数据(调用onBindViewHolder)
mAttachedScrap 未与RecyclerView分离的ViewHolder列表

二级缓存:屏幕外缓存(mCachedViews)

用来缓存移除屏幕之外的 ViewHolder,默认情况下缓存容量是 2,可以通过 setViewCacheSize 方法来改变缓存的容量大小。如果 mCachedViews 的容量已满,则会优先移除旧 ViewHolder,把旧ViewHolder移入到缓存池RecycledViewPool 中。

三级缓存:自定义缓存(ViewCacheExtension)

给用户的自定义扩展缓存,需要用户自己管理 View 的创建和缓存,可通过Recyclerview.setViewCacheExtension()设置。

四级缓存:缓存池(RecycledViewPool )

 //每个 ViewType 默认最多缓存 5 个
 private static final int DEFAULT_MAX_SCRAP = 5;
 //二维数组用来缓存viewHolder对象
     static class ScrapData {
            final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
        }
        SparseArray<ScrapData> mScrap = new SparseArray<>();
// 在LayoutManager调用onLayoutChildren 执行了detachAndScrapAttachedViews方法,并循环遍历执行每个子条目的scrapOrRecycleView方法,这时候就会有第一次调用缓存池的情况:

//在recycleViewHolderInternal 方法执行的时候 调用addViewHolderToRecycledViewPool,将viewholder对象添加到缓存池
 void recycleViewHolderInternal(ViewHolder holder) {
......
  	if (forceRecycle || holder.isRecyclable()) {
			......
      	cached = true;
  	}
 		if (!cached) {
			addViewHolderToRecycledViewPool(holder, true);
			recycled = true;
		}
......
}

void addViewHolderToRecycledViewPool(@NonNull ViewHolder holder, boolean dispatchRecycled){
			......
            getRecycledViewPool().putRecycledView(holder);
        }

ViewHolder 缓存池,在mCachedViews中如果缓存已满的时候(默认最大值为2个),先把mCachedViews中旧的ViewHolder 存入到RecyclerViewPool。如果RecyclerViewPool缓存池已满,就不会再缓存。从缓存池中取出的ViewHolder ,需要重新调用bindViewHolder绑定数据。

public ScrapData getScrapDataForType(int viewType) {
    ScrapData scrapData = mScrap.get(viewType);
    if (scrapData == null) {
        scrapData = new ScrapData();
        mScrap.put(viewType, scrapData);
    }
    return scrapData;
}
  • 按照 ViewType 来查找 ViewHolder
  • 可以多个 RecyclerView 共享 RecycledViewPool

RecyclerViewPool底层是使用了SparseArray来分开存储不同ViewType的ViewHolder集合

在这里插入图片描述

缓存策略

Recyclerview在获取ViewHolder时按四级缓存的顺序查找,如果没找到就创建。其中只有RecycledViewPool找到时才会调用 onBindViewHolder,其它缓存不会重新bindViewHolder 。 流程如下 :

在这里插入图片描述
RecyclerView优化

1.降低item的布局层次

降低item布局层级,可以减少界面创建的渲染时间,使用约束布局等。

2.去除冗余的setOnItemClick事件

直接在onBindViewHolder方法中创建一个匿名内部类的方式来实现setOnItemClick是不可取的,这会导致在RecyclerView快速滑动时创建很多对象,优化方法为:事件的绑定和viewholder对应的rootView进行绑定

3.复用pool缓存

如果存在RecyclerView中嵌套RecyclerView的情况,可以考虑复用RecyclerViewPool缓存池,减少开销。

总结

通过了解RecyclerView的四级缓存,我们可以知道,RecyclerView最多可以缓存 N(屏幕最多可显示的item数) + 2 (屏幕外的缓存) + 5*M (M代表M个ViewType,缓存池的缓存),只有RecycledViewPool找到时才会重新调用 onBindViewHolder。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值