Android-RecycleView
RecycleView
基本使用
需要设置布局管理器LayoutManager,用于表示是哪种方式显示,可以使用API提供的LinearLayoutManager(以垂直或水平滚动)、GridLayoutManager(网格方式显示)、StaggeredGridLayoutManager (分散对齐网格中显示,瀑布流),也可以自定义LayoutManager。
需要设置RecyclerView.Adapter。
如果需要控制Item间的间隔,需要使用RecyclerView.ItemDecoration,API提供DividerItemDecoration,一般特殊需求通过自定义ItemDecoration,然后通过onDraw方法实现达到需求。
如果需要要控制Item增删的动画,需要使用RecyclerView.ItemAnimator,API提供DefaultItemAnimator,也可以自定义。
LayoutManager自定属于UI绘制,这里不再详解。
RecycleView的缓存机制
我们知道RecyclerView在绘制View的时候是根据适配器规则,一项一项绘制的,如果我们每次显示或者移除都去创建和销毁,那会非常占用内存和性能,可能会导致频繁的GC或者OOM。
RecyclerView的缓存机制有:四级缓存
根据不同的状态可以分为:屏幕内缓存、屏幕外缓存、自定义缓存、缓存池。
RecyclerView是通过内部类Recycler来管理缓存。
屏幕内缓存
缓存屏幕中显示的ViewHolder,这些ViewHolder会缓存在mAttachedScrap、mChangedScrap中 。
mChangedScrap 表示数据已经改变的ViewHolder列表,需要重新绑定数据(调用onBindViewHolder)
mAttachedScrap 未与RecyclerView分离的ViewHolder列表
屏幕外缓存
缓存移除屏幕之外的 ViewHolder,默认是 2(缓存容量)。
如果 mCachedViews 的容量已满,则会优先移除旧 ViewHolder,把旧ViewHolder移入到缓存池RecycledViewPool 中。
API提供 setViewCacheSize(int size) 方法来设置缓存的容量大小。

自定义缓存
自定义扩展缓存,供开发者使用,需要开发者自己管理 View 的创建和缓存,可通过Recyclerview.setViewCacheExtension()设置。需自行实现ViewCacheExtension接口实现。



缓存池
ViewHolder 缓存池,流程为:在mCachedViews中如果缓存已满的时候(默认最大值为2个),先把mCachedViews中旧ViewHolder 存入到RecyclerViewPool。如果RecyclerViewPool缓存池已满,就不会再缓存。
从缓存池中取出的ViewHolder ,需要重新调用bindViewHolder绑定数据。
按照 ViewType 来查找 ViewHolder
每个 ViewType 默认最多缓存 5 个
可以多个 RecyclerView 共享 RecycledViewPool
RecyclerViewPool底层是使用了SparseArray来分开存储不同ViewType的ViewHolder集合,Android推出的SparseArray、ArrayMap用来代替HashMap,在某些情况下提升性能。详细看优化篇。
策略
Recyclerview在获取ViewHolder时按四级缓存的顺序查找,如果没找到就创建。其中只有RecycledViewPool找到时才会调用 onBindViewHolder,其它缓存不会重新bindViewHolder 。
