赞
踩
笔者希望做一个系列,整理 Android 基础技术,本章是关于 RecyclerView
mAttachedScrap(屏幕内),mCacheViews(屏幕外),mViewCacheExtension(自定义缓存),mRecyclerPool(缓存池)
RecyclerView的局部刷新就是依赖Scrap的临时缓存,当我们通过notifyItemRemoved(),notifyItemChanged()通知item发生变化的时候,通过mAttachedScrap缓存没有发生变化的ViewHolder,其他的则由mChangedScrap缓存,添加itemView的时候快速从里面取出,完成局部刷新。
注意,如果我们使用notifyDataSetChanged()来通知RecyclerView刷新,屏幕上的itemView被标记为FLAG_INVALID并且未被移除,所以不会使用Scrap缓存,而是直接扔到CacheView或者RecycledViewPool池中,回来的时候重新走一次绑定数据。
注意:itemE并没有出现在屏幕中,它不属于Scrap管辖的范围,Scrap只会缓存在屏幕中已经加载出来的itemView的holder。

- public static class RecycledViewPool {
- private static final int DEFAULT_MAX_SCRAP = 5;
- static class ScrapData {
- final ArrayList<ViewHolder> mScrapHeap = new ArrayList<>();
- int mMaxScrap = DEFAULT_MAX_SCRAP;
- }
- SparseArray<ScrapData> mScrap = new SparseArray<>();
- }
-
可以看出,RecycledViewPool中定义了SparseArray<ScrapData> mScrap,它是一个根据不同itemType来保存静态类ScrapData对象的SparseArray,ScrapData中包含了ArrayList<ViewHolder> mScrapHeap ,mScrapHeap是保存该itemType类型下ViewHolder的ArrayList。
缓存池定义了默认的缓存大小DEFAULT_MAX_SCRAP = 5,这个数量不是说整个缓存池只能缓存这多个ViewHolder,而是不同itemType的ViewHolder的list的缓存数量,即mScrap的数量,说明最多只有5组不同类型的mScrapHeap。mMaxScrap = DEFAULT_MAX_SCRAP说明每种不同类型的ViewHolder默认保存5个,当然mMaxScrap的值是可以设置的。这样RecycledViewPool就把不同ViewType的ViewHolder按类型分类缓存起来。
同时也是能做到局部刷新的原理
在RecyclerView重新布局onLayoutChildren()或者填充布局fill()的时候,会先把必要的item与屏幕分离或者移除,并做好标记,保存到list中,在重新布局时,再将ViewHolde拿出来重新一个个放到新的位置上去。
(1)如果是RecyclerView不滚动情况下缓存(比如删除item),重新布局时,把屏幕上的ViewHolder与屏幕分离下来,存放到Scrap中,即发生改变的ViewHolder缓存到mChangedScrap中,不发生改变的ViewHolder存放到mAttachedScrap中;剩下ViewHolder的会按照mCachedViews>RecycledViewPool的优先级缓存到mCachedViews或者RecycledViewPool中。
(2)如果是RecyclerVIew滚动情况下缓存(比如滑动列表),在滑动时填充布局,先移除滑出屏幕的item,第一级缓存mCachedViews优先缓存这些ViewHolder,但是mCachedViews最大容量为2,当mCachedViews满了以后,会利用先进先出原则,把旧的ViewHolder存放到RecycledViewPool中后移除掉,腾出空间,再将新的ViewHolder添加到mCachedViews中,最后剩下的ViewHolder都会缓存到终极回收池RecycledViewPool中,它是根据itemType来缓存不同类型的ArrayList<ViewHolder>,最大容量为5。
RecyclerView 有5个缓存池子,mChangedScrap、mAttachedScrap、mCachedViews、mViewCacheExtension、mRecyclerPool,除了mViewCacheExtension是系统提供给开发者拓展的没有用到之外,还有四个池子是参与到复用流程中的。
当RecyclerView要拿一个复用的ViewHolder时,如果是预加载,则会先去mChangedScrap中精准查找(分别根据position和id)对应的ViewHolder,如果有就返回,如果没有就再去mAttachedScrap和mCachedViews中精确查找(先position后id)是不是原来的ViewHolder,如果是说明ViewHolder是刚刚被移除的,如果不是,则最终去mRecyclerPool找,如果itemType类型匹配对应的ViewHolder,那么返回实例,让它重新绑定数据,如果mRecyclerPool也没有返回ViewHolder才会调用createViewHolder()重新去创建一个。
这里需要注意:在mChangedScrap、mAttachedScrap、mCachedViews中拿到的ViewHolder都是精准匹配,但是mChangedScrap的是发生了变化的,需要调用onBindViewHolder()重新绑定数据,mAttachedScrap和mCachedViews没有发生变化,是直接使用的,不需要重新绑定数据,而mRecyclerPool中的ViewHolder的内容信息已经被抹除,需要重新绑定数据。所以在RecyclerView来回滚动时,mCachedViews缓存池的使用效率最高。
总的来说:RecyclerView着重在两个场景缓存和回收的优化,一是:在数据更新时,使用Scrap进行局部更新,尽可能复用原来viewHolder,减少绑定数据的工作;二是:在滑动的时候,重复利用原来的ViewHolder,尽可能减少重复创建ViewHolder和绑定数据的工作。最终思想就是,能不创建就不创建,能不重新绑定就不重新绑定,尽可能减少重复不必要的工作。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。