前言
有一定开发经验的朋友基本都知道,RecyclerView有一个Item复用的功能
就是将划出的Item,重新利用,给将要划入的Item使用
从代码上来说,就是将不再使用的ViewHolder,与新划入的Item绑定
这样就不需要重新执行onCreateViewHolder,只要执行onBindViewHolder,然后将其摆放到新的布局位置即可
这是RecyclerView缓存机制最核心的东西,这里我们要详细讲解下,其背后具体是如何工作的
Recycler
这个类是负责RecyclerView缓存工作的核心类,它的类结构如下
public final class Recycler {
ArrayList mAttachedScrap = new ArrayList();
ArrayList mChangedScrap = null;
ArrayList mCachedViews = new ArrayList();
ViewCacheExtension mViewCacheExtension = null;
RecycledViewPool mRecyclerPool;
}
可以看到,Recycler中使用了四级缓存机制
也有人说是二级缓存机制,这是由于关注点不同,忽略了其中的一部分
现在我们来看看这些缓存对象的具体作用
-
mAttachedScrap:ViewHolder已经与某个position的Data绑定,且Data的位置和数值未发生改变
-
mChangedScrap:ViewHolder已经与某个position的Data绑定,但是由于单个元素被修改,或两个元素位置进行了拖拽呼唤,需要重新绑定Data
-
mCachedViews:ViewHolder被移除,或者Adapter调用了notifyDataSetChanged重置了整个数据源,此时缓存的ViewHolder会被从Scrap移动到Cache中。但mCachedViews数量是有上限的,只会保存最近移入的几个对象
-
mViewCacheExtension:用户自定义的缓存机制,如果前面都找不到,则到这里来找,如果用户没有指定,则继续下一步
-
RecycledViewPool:专业的缓存池,它会为每种ViewType创建若干个ViewHolder。如果用户没有指定mViewCacheExtension的话,那么所有的ViewHolder最终都来自这里,因为Scrap和Cache都只负责存储,并没有生产功能,当Scrap和Cache中都没有可用的ViewHolder时,则通过RecycledViewPool来创建,只有它会调用onCreateViewHolder方法,Scrap和Cache都只会执行onBindViewHolder方法。另外,RecycledViewPool是可以在多个RecyclerView之间共享的,虽然实际用到的场景不多
常用情景分析
其实有了上面的讲解,大家已经大概知道怎么一回事情了
我没有像网上的其它博客一样,一上来就各种贴源码,那样很容易头晕,最后重点反而被忽略了
大家弄懂原理后,再去看其它博主贴的源码,就很容易了
我再给大家列举下常用场景下,Recycler是如何更新缓存的,这样更贴近实际
我这边博客和其他人最大的区别在于,别人重点讲的是代码,我重点讲的是业务流程
- notifyItemChanged:修改单个元素,将对应的ViewHolder移到mChangedScrap中,UI刷新时会重新执行onBindViewHolder
- notifyItemMoved:交换两个元素,将两个元素对应的ViewHolder都移到mChangedScrap中,UI刷新时会重新执行onBindViewHolder
- notifyItemRemoved:移除单个元素,将对应的ViewHolder移到mCachedViews中,受影响的其它元素更新Index
- notifyDataSetChanged:重置整个数据源,将所有的ViewHolder移到mCachedViews中,超出容量的丢弃,刷新UI时通过RecycledViewPool重新创建
detach和remove的区别
RecyclerView有两个移除ItemView的功能,一个是detachAndScrap,一个是removeAndRecycle
detach只是临时将ItemView移除,后面有可能重新添加回来,所以将其放到Scrap缓存中
remove是永久性移除,所以将其放到Cache缓存中