RecyclerView复用机制和缓存机制

  • Post author:
  • Post category:其他



1. RecyclerView复用机制流程:


以onTouchEvent作为切入口:

在这里插入图片描述

时序图中关键流程简要备注:

  1. 第1步, 代码切入点:

    1)上下滑动会产生ViewHolder–>从OnTouchEvent()的MotionEvent.ACTION_MOVE事件处理;

    2) 从onLayout作为切入口

  2. 第3步,mLayout.scrollVerticallyBy()中的mLayout指LayoutManager类对象,它是RecyclerView内部的 抽象类,LinearLayoutManager继承RecyclerView.LayoutManager,之后以上下滑动为例进行阐述;

  3. 第5步,fill()—>填充item,fill(RecyclerView.Recycler recycler, LayoutState layoutState,

    RecyclerView.State state, boolean stopOnFocusable)方法中的第一个参数RecyclerView.Recycler表示处理缓存(回收)复用

  4. 第7步,View view = layoutState.next(recycler);表示从缓存中拿到一个View进行复用处理,拿到view之后执行addView(view)添加到布局中。

  5. 第8步, recycler.getViewForPosition()–>根据位置拿到复用的View

  6. 第10步,tryGetViewHolderForPositionByDeadline这个非常重要 –》这个方法处理复用机制

  7. 第11步,getChangedScrapViewForPosition从mChangedScrap.get(i)(通过position和id进行获取)中去获取ViewHolder,mChangedScrap是一个ArrayList集合

  8. 第13步,如果从mChangedScrap集合中没有获取到,则利用getScrapOrHiddenOrCachedHolderForPosition方法通过

    position

    ,首先从mAttachedScrap集合中,如果从mAttachedScrap集合中没获取到,再从mCachedViews集合中进行获取;

  9. 第16步,如果从mCachedViews集合中没有获取到ViewHolder,则利用采用getScrapOrCachedViewForId通过

    stable id

    进行查找,流程跟第13步类似,首先从mAttachedScrap集合中没获取到,再从mCachedViews集合中进行获取;

  10. 第19步,mViewCacheExtension是一个抽象类RecyclerView.ViewCacheExtension的对象实例, mViewCacheExtension.getViewForPositionAndType 这个接口其实是google工程师让用户自定义的,先自定义缓存,再自定义复用,这一步一般不要关,不会处理;

  11. 第20步,如果在第19步还是没获取到,就从缓存池中进行获取,调用getRecycledViewPool().getRecycledView()

  12. 第21步,如果从上面的流程中还没有获取到,就通过适配器创建一个ViewHolder,执行mAdapter.createViewHolder()流程,mAdapter指RecyclerView的内部类Adapter;createViewHolder()方法内部会执行onCreateViewHolder()方法,该方法是一个抽象方法

  13. 第23步,假如ViewHolder容器能够拿到,则会执行tryBindViewHolderByDeadline()方法进行绑定数据,tryBindViewHolderByDeadline()–>mAdapter.bindViewHolder()–> onBindViewHolder(),onBindViewHolder是一个抽象方法;

缓存和复用的对象是什么?–> ViewHolder –>可以简单理解为itemView


2. 四级缓存

  1. mChangeScrap与mAttachedScrap

    用来缓存还在屏幕内的ViewHolder

    局部刷新,保存在mAttachedScrap中的直接拿来用,主要是性能优化处理

    mChangeScrap主要是用于动画处理

  2. mCachedViews –> 可以通过setMaxRecycledViews()更改默认大小

    用来缓存移除屏幕之外的ViewHolder

    ArrayList mCachedViews 默认大小 –> DEFAULT_CACHE_SIZE = 2 –> 可以通过setViewCacheSize()更改默认大小

    ArrayList scrapHeap 默认大小 –> DEFAULT_CACHE_SIZE = 5

  3. mViewCacheExtension

    这个的创建和缓存完全由开发者自己控制,系统未往这里添加数据

  4. RecycledViewPool

    ViewHolder缓冲池

以onLayout作为切入口:

在这里插入图片描述


复用 是从 缓存中去取,先有缓存,在有复用。


3. 缓存


在这里插入图片描述

时序图中关键流程简要备注:

  1. 第2步,通过for循环不断获取缓存
  2. 第3步,scrapOrRecycleView()这个方法比较关键,分两者情况进行处理缓存

    ① recycler.recycleViewHolderInternal(viewHolder)

    缓存到mCachedViews(默认大小2)和 RecycledViewPool中(默认大小5)。

    ② recycler.scrapView(view)

    根据下面的条件来判断是缓存到mAttachedScrap 还是mChangedScrap中。—》这个就是一级缓存
if (holder.hasAnyOfTheFlags(ViewHolder.FLAG_REMOVED | ViewHolder.FLAG_INVALID)
                    || !holder.isUpdated() || canReuseUpdatedViewHolder(holder))
  1. 第5步,如果mCacheView满了,取出ViewHolder放到根据viewType(第7步)放到RecycledViewPool(第6步)中,并将mCachedViews集合中第0个位置的remove;


mCachedViews和RecycledViewPool缓存流程:


在这里插入图片描述


mCacheView结构:队列



RecycledViewPool结构:有点类似hashMap

1)屏幕从下往上滑动,滑出1个ViewHolder(item),先放到mCacheView缓存中的index 为0的位置,如果屏幕在滑出1个item,放到index为1的位置;

2)如果屏幕此时在滑出一个ViewHolder,则将mCacheView缓存中index 为0的位置的ViewHolder,根据其ViewType,放到RecycledViewPool缓存对应的ScrapData中,ScrapData中最多只能放5个,超过5就return丢掉,如果没有满就会先将ViewHolder先置空(复位),再添加到ScrapData集合中;

3)将原来mCacheView缓存中index 为1的位置ViewHolder,放到mCacheView缓存中index 为0的位置,再将滑出屏幕的ViewHolder放到mCacheView缓存中index 为1的位置中。

onCreateViewHolder –> 缓存拿不到ViewHolder才会调用的,而不是拿不到数据

从缓存池中复用ViewHolder:需要调用 onBindViewHolder

从CacheView中复用ViewHolder:不用调用 onBindViewHolder

从缓存中没有拿到ViewHolder:会调用 onCreateViewHolder 和 onBindViewHolder


ListView与RecyclerView的区别:


ListView:只能在垂直方向滑动

RecyclerView:支持水平方向滑动,垂直方向滑动,多行多列瀑布流的方式等

ListView:有几个默认的Adapter,分别是ArrayAdapter、CursorAdapter和SimpleCursorAdapter

RecyclerView:Adapter需要自己实现

ListView:拥有子Item的监听函数:AdapterView.OnItemClickListener

RecyclerView:需要自己实现接口,来实现子Item的点击事件,虽然比较麻烦,但是扩展性好

ListView:并不强制使用ViewHolder,如果要使用,则需要自己定义,如果不使用,ListView每次getView()的时候都需要去findViewById,会造成性能下降,滑动卡顿等,所以推荐使用ViewHolder

RecyclerView:必须使用ViewHolder

ListView:两级缓存

1)mActiveViews 用于屏幕内ItemView快速重用

2)mScrapViews 用于缓存离开屏幕的ItemView

RecyclerView:四级缓存

1)mChangeScrap 与 mAttachedScrap 用于屏幕内ItemView 快速重用

2)mCachedViews 默认上限为2,即缓存屏幕外2个ItemView

3)mViewCacheExtension 用户自定义,一般不使用

4)RecycledViewPool 默认上限为5

缓存对象不同,RecyclerView缓存的是ViewHolder,ListView缓存的是View。



版权声明:本文为xuyin1204原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。