一、缓存
①布局缓存,mAttachedScrap 和 mChangedScrap,布局完成之后就会清空
RecyclerView 滑动场景来说,新卡位的复用以及旧卡位的回收, 不触发 mChangedScrap 和 mAttachedScrap
notifyItemChanged/rangeChange,此时如果Holder发生了改变,那就放入changeScrap,反之放入AttachScrap。
②mCachedViews
当列表滑动出了屏幕时,View已经从RecyclerView中detached或removed,ViewHolder会被缓存在 mCachedViews ,其大小由mViewCacheMax决定,默认DEFAULT_CACHE_SIZE为2,可通过Recyclerview.setItemViewCacheSize()动态设置。
存放的 ViewHolder 只有原本位置的卡位才能复用,不用重新绑定数据。
③ViewCacheExtension
可以自己实现ViewCacheExtension类实现自定义缓存,通过Recyclerview.setViewCacheExtension()设置。
④RecycledViewPool
ViewHolder首先会缓存在 mCachedViews 中,当超过了个数(比如默认为2), 就会添加到 RecycledViewPool 中。RecycledViewPool 会根据不同ViewType把ViewHolder分别存储在不同的列表中,每个ViewType最多缓存DEFAULT_MAX_SCRAP = 5 个ViewHolder。
复用时,需要重新绑定数据。
二、滑动回收复用
滑动场景触发mCachedViews、RecycledViewPool缓存。
先复用再回收!!
①如下图,RecyclerView 向下滑动日志,第三行5个卡位的显示都是重新创建的 ViewHolder。
mCachedViews 优先级要高于 RecyclerViewPool,前者默认大小2,后者为5。所以,当第三行显示出来后,第一行的5个卡位被回收,先缓存在 mCachedViews,满了再移出到 ViewPool 里,所以5个卡位有2个缓存在 mCachedViews 里,3个缓存在 ViewPool。
至于是哪2个缓存在 mCachedViews,是由 LayoutManager 控制。这里例子使用的是 GridLayoutManager,滑动时的回收逻辑则是在父类 LinearLayoutManager 里实现,回收第一行卡位时是从后往前回收,所以最新的两个卡位是0、1,会放在 mCachedViews 里,而2、3、4的卡位则放在 ViewPool 里。
②所以,当再次向上滑动时,第一行5个卡位会去mCachedViews、RecycledViewPool里找复用,因为mCachedViews 里存放的 ViewHolder 只有原本位置的卡位才能复用,所以0、1两个卡位都可以直接去 mCachedViews 里拿 ViewHolder 复用,而且这里 ViewHolder 不用重新绑定数据。
至于2、3、4卡位则去 ViewPool 里找,刚好 ViewPool 里缓存着3个 ViewHolder,触发 onBindViewHolder() 方法,重新绑定数据,因此只有三个卡位需要重新绑定数据。
接着RecyclerView 向下滑动
RecyclerView 共创建17个 ViewHolder,是因为在第四行的卡位要显示出来时,ViewPool 里只有3个缓存,而第四行的卡位又用不了 mCachedViews 里的2个缓存(不是原本位置的卡位),所以就需要重新创建2个 ViewHodler 来给第四行最后的两个卡位使用。