之前有总结过ListView的缓存机制和RecyclerView的缓存机制,那这两种到底有什么区别呢
简单了解下缓存的基本原理
1)在初始化onLayout过程中,都有一个 mAttachedxxx的集合,临时存在即将显示的第一屏的view,在最后一次onLayout结束之后,会从将该mAttachedxxx里面的view渲染到第一屏页面上。
2)当向上滑动过程中,都是先将滑出屏幕的view放到Recycle中,然后从Recycle中经过转换,将该view渲染到界面上。只是在缓存处理和缓存的内容上有点区别。
3)在数据源发生变化的时候,xxxxxxxxxx
发现缓存机制的层级数差别
ListView和RecyclerView的缓存层级数不同,RecyclerView支持开发者自定义缓存逻辑,支持RecyclerViewPool缓存池,同时支持多个RecyclerView共用该RecyclerViewPool。
ListView(两级缓存)
缓存集合 | 是否需要重新创建view | 是否需要重新设置view数据 | 作用域 | 集合元素变化 |
mActiveViews | 否,直接将第一次onLayout创建的view添加到该集合中 | 否,因为就是第一屏的view重新渲染到ListView中 | add:发生在每次onLayout或初始化的第二次onLayout; | 每次onLayout的当前view集合 |
clear:从集合中取出该元素,则马上将该集合中的元素置为null | ||||
mScrapViews | 否,将正在显示的view添加到该集合中, | 是,需要重新调用getView去绑定数据,因为不同position在复用该view时,对应该位置的数据源是不一致的,通常我们只会去用该view,而重新设置数据 | add:显示另外一屏view时; | 1)若数据源没有发生变化始终为第一屏的view集合; 2)若数据源发生变化,会将所有的view都加入到该集合中 3)若adapter发生变化,该集合中的view才会发生变化 |
clear:与adapter保持一致,只有当adapter数据发生变化的时候,即调用setAdapter的时候,才会清空该集合中的元素 |
RecylerView(四级缓存)
缓存集合 | 是否需要重新创建view | 是否需要重新设置view数据 | 作用域 | 集合元素变化 |
mAttachedView | 否 | 否 | add:发生在每次onLayout或初始化的第二次onLayout; | |
clear: | ||||
mCacheViews
| 否,默认的保存的两个view和view的数据 | 否,默认的保存的两个view和view的数据,因为保存的就是对应position的view和数据,只要位置对了才可以使用 | add:显示另一屏的view时,会将移除屏幕的view添加到该集合中,最大容量为可以设置,默认为2 | 不同的LayoutManager缓存的holder集合元素不一致,在变化中,默认的2个 |
clear:当超出最大容量时,只会移除一个元素; 清除所有元素:与adapter保持一致,只有当adapter数据发生变化的时候,即调用setAdapter的时候,也会清空该集合中的元素。 | ||||
mViewCacheExtension | 不直接使用,需要开发者定义 | |||
mRecyclerPool | 否,缓存view,但数据不缓存 | 是,需要重新执行onBindViewHolder去重新设置数据 | add:将mCacheViews集合中的个数超过设置的值(默认为2)时,则将mCacheViews里面的元素add到该集合中 | 元素发生变化,默认的不同类型的viewType对应的为5个 同时可以实现多个RecyclerView共用一个ViewPool |
clear: |
从上面的表格对比中可以看出:
RecyclerView在缓存层级上,只是多了一个mCacheViews,可以保证屏幕外的view在进入到屏幕时无须进行绑定数据,但是这里也必须是对应position的view才可以复用
发现缓存内容的不同
缓存内容 | 缓存之后的复用 | 缓存和复用的顺序 | |
ListView | View,需要每次都要绑定数据 | 需要缓存的时候,将当前屏幕的所有view都添加到二级缓存mScrapViews,在复用的时候全都需要bindView | 先缓存在复用,所以在数据没有发生变化的前提下,第二屏数据就可以复用缓存的view; 即使数据发生变化,在加载的view,也是可以直接复用view |
RecyclerView | RecyclerView.ViewHolder=View+ViewHolder(findViewById)+flag,有的时候可以直接拿来使用,有的时候仅仅需要绑定数据就可以了 | 需要缓存的时候,会根据mCacheViews和mRecyclerPool里的个数和顺序依次添加,用来区分加入的view是否需要重新bindView | 先复用在缓存,所以在数据没有发生变化的前提下,如果显示第二屏的view,仍要从create-bind,直到第三屏的view才可使用缓存的view。 |
下面用流程图来简单的说明下缓存过程
ListView的缓存流程
RecyclerView的缓存流程
缓存流程和ListView差不多,只不过调用的方法名不同,多了两层缓存,可以参见RecyclerView的Recycler
总结
像平常的简单列表展示静态view的时候,其实我觉得ListView和RecyclerView没有太多区别,但是RecyclerView的优势在于:
1)局部刷新,减少调用bindView
2)频繁更新数据源和view的显示的内容
3)支持Item的动画
4)支持多种列表,像普通的列表、网格、瀑布流