RecyclerView缓存复用的简单理解


前言

文中材料都来自网络查找,有错的话可以评论交流

一、RecyclerView的四级缓存是什么?

  首先需要对RecyclerView如何滚动显示其子项有一定的了解,这与ViewGroup的显示流程有关,ViewGroup需要依次走过onMeasure()方法、onLayout()方法、onDraw()方法,依次测量,布局,绘制。RecyclerView监听到滑动的操作后,重新调用onLayout()来排列和布局子 View ,这样就有了滚动的能力。

  • 一级缓存:mAttachedScrap 和 mChangedScrap ,为LayoutManager每次布局子View之前,那些已经添加到RecyclerView中的Item以及被删除的Item的临时存放集合,一级缓存都是屏幕内的
       - mAttachedScrap 存储的是当前还在屏幕中的 ViewHolder。
       - mChangedScrap 存储的是当前还在屏幕中、数据已经改变的 ViewHolder 。

  • 二级缓存:mCachedViews ,用来缓存移除屏幕之外的 ViewHolder。
      - 默认情况下缓存容量是 2,可以通过 setViewCacheSize 方法来改变缓存的容量大小
      如果 mCachedViews 的容量已满,则会根据 FIFO (先进先出)的规则移除旧 ViewHolder。
      取出ViewHolder(即将重用)时无须重新绑定数据(不用执行onBindViewHolder方法)
      

  • 三级缓存:ViewCacheExtension ,开发给用户的自定义扩展缓存,需要用户自己管理
    View 的创建和缓存.相当不常用。
      

  • 四级缓存:RecycledViewPool ,ViewHolder 缓存池,在有限的 mCachedViews 中如果存不下新的
    ViewHolder 时,就会把 ViewHolder 存入RecyclerViewPool 中。

    • 按照 Type 来查找 ViewHolder,与之相比,上面的都是通过index去获取 ViewHolder的
    • 每个 Type 默认最多缓存 5 个
    • 可以多个 RecyclerView 共享 RecycledViewPool

二、流程分析

1.前提条件

用了一个Recyclerview,右边添加一个收藏按钮,列表数据item类里设置一个标志,如下代码,若istrue为true则收藏显示,若为false,则不显示。效果如下图,只有第一个图片设置为true。

 public test(String text, int imageId, boolean istrue) {//item子类
        this.text = text;
        this.imageId = imageId;
        this.istrue = istrue;
    }
tests.add(new test("我的天啊"+j++,R.drawable.soucang1,true));//只有第一个设置为true

         for (int i=0;i<40;i++){

                 tests.add(new test("妈妈啊"+j++,R.drawable.soucang1,false));

             tests.add(new test("爸爸啊"+j++,R.drawable.soucang1,false));
             tests.add(new test("姐姐啊"+j++,R.drawable.soucang1,false));
         }
但是当往下滑动会发现,下面的图片也显示了五角星收藏,这就是复用了之前绘制的图片,效果如下,仔细看会发现复用还有一定的规律。第1,13,25,37,42个显示五角星,每隔12个显示一个 但是当我不断上滑下滑,就会出现如下情况:五角星变多了

从上我们可以推断recyclerview的viewholder复用的流程。

2.Recyclerview复用流程

  • 一级缓存,mAttachedScrap缓存的是屏幕内能看见的子项

  • 如上面的例子,第一个为带星子项(带星星的那个子项),开始向上滑动,带星子项,进入二级缓存mCachedViews,第二个子项也看不见时,第二个子项也进入了二级缓存mCachedViews。

  • 由于二级缓存mCachedViews缓存容量为2,此时二级缓存已满,根据先进先出原则,带星子项首先进入了四级缓存RecycledViewPool中。

  • 四级缓存RecycledViewPool容量为5,当界面继续向上滑动,子项继续进入二级缓存mCachedViews,先进先出原则,二级缓存的子项溢出,进入四级缓存,直到四级缓存开始满了,也就是说此时,带星子项在四级缓存的最上面,即将溢出。

  • 继续向上滑动,带星子项溢出被拿到界面,也就是说,我们复用了这个带星子项,这也就是为什么,我们明明只设置了一个带星子项,但会每隔12个就显示一个子项。当你一直向下滑动,因为它一直在被复用,所以你看到的始终是同一个子项。

3.复用流程2

onCreateViewHolder,onBindViewHolder里的代码如下:

 public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
     View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.recycle_item,parent,false);
     ViewHolder viewHolder=new ViewHolder(view);
        Log.d("傻", "onCreateViewHolder: ");
        return viewHolder;
    }

    ReAdapter(List<test> list){
     tests=list;
    }


    @Override
    public void onBindViewHolder(@NonNull final ViewHolder holder, int position) {
    final test tes=tests.get(position);
        Log.d("傻", "onBindViewHolder: "+"我要绑定数据"+position+tes.istrue);
        holder.imageView.setImageResource(tes.imageId);
        holder.textView.setText(tes.text);
if(tes.istrue){
    holder.imageView.setVisibility(View.VISIBLE);
    Log.d("傻", "onBindViewHolder: "+"我要求能看见图片"+position);
}
holder.itemView.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        Log.d("傻", "onClick: ");
        holder.imageView.setImageResource(R.drawable.soucang2);
        tes.istrue=true;

    }
});

    }

当向上滑动,其日志打印如下:

最开始,由于屏幕内和缓存池里并没有子项可以复用,所以经过onCreateViewHolder创建,onBindViewHolder绑定数据,创建了一个个viewholder。继续向下滑动,打印日志如下

可以看到后面没有再onCreateViewHolder,说明这些子项(ViewHolder)一直在被循环复用,只需要重新绑定数据就可以再度使用。

为什么不断来回滑动,带星子项变得越来越多?

因为,当你向上滑动,此时带星子项进入缓存池,当你再向上滑动,如果此时带星子项没有正好溢出,被复用到你设置的第一个应该拥有星星的子项时,就会重新绘制一个,此时缓存池有一个带星子项,屏幕内也有一个带星子项,当你不断来回滑动,就可能不断重新绘制一个带星子项,所以会变得越来越多。

注意

  • 复用的其实是viewholder。这里我开始以为复用的是viewholder这个类,始终没理解,这个类和绘制出来的view有什么联系,后来我才发现,我把listview里的viewholder和recyclerview的holder弄混了。listview里的viewholder,是自己定义的类,内含一些数据变量,而recyclerview里的viewholder传进了View类的参数,itemview。
    所以我们可以理解为复用的就是一个个绘制好的view或者说卡片。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值