RecyclerView(待补充源码)
RecyclerView
结构
- View
- Adapter 负责将数据转化为itemview
- LayoutManager 负责测量摆放itemview与触摸反馈
RecyclerView.onMeasure() –> LayoutManager.onMeasure()
RecyclerView.onLayout()
–> dispatchLayout()
–> dispatchLayoutStep2()
–>LayoutManager.onLayoutChildren()
对比ListView
Adapter
ListView中复用的是View
RecyclerView复用的是ViewHolder
缓存
ListView两级缓存
RecyclerView四级缓存
动画
ListView动画实现比较麻烦,无法具体得知某个item的改变,也就是无法局部刷新
ItemAnimator
ItemDecoration
绘制分割线或者滚动条之类的元素
运行机制
RecyclerView –> LayoutManager –> Recyler –>Adapter.onCreateViewHolder() 或onBindViewHolder()产生ViewHolder返回Recycler,Recycler再取出View给LayoutManager
ListView复用机制
复用池
View[] mActiveViews = new View[0]
界面上的view没有发生变化时用到,元素会直接复用,不用重新绑数据,比如外部requestLayout,比如早版本sdk在第一次绘制时会触发多次requestLayout
ArrayList<View>[] = mScrapViews
一个ArrayList数组,每一个ArrayList代表一种ViewType在回收池中的一组View,ViewType就是数组索引,所以ListView的ViewType是连续的int值,需要重新绑数据
notifyDataSetChanged()
会把当前界面所有view取出放入mScrapViews,然后取出重新绑定
滑动
滑出的item会把view放入mScrapViews
进入的item会取出,也就是getView中的convertView,如果没有就创建新VIew
RecyclerView的缓存
Recycler
ArrayList mCacheViews
类似mActiveViews,默认最多放两个ViewHolder,作用场景是,向上滑两个item出去,再向下滑两个,此时数据没有变动,可以直接命中mCacheViews中刚缓存的view,直接用,不会走onbindviewholder
mViewCacheMax设置mCacheViews容积
RecyclerViewPool
#RecyclerViewPool
private static final int DEFAULT_MAX_SCRAP = 5 // mScrapHeap中元素最大值,如果itemtype种类少可以设置多点,反之少点
SparseArray<ScrapData> mScrap // 这种设置itemtype就不需要是连续的int值了
class ScrapData {
ArrayList<ViewHolder> mScrapHeap
}
一直向下滑多于三个item回收,mCacheViews中就会去一个给mScrap,然后加入最新的
向上滑回来,先看mCacheViews,在看mScrap,都不需要重新绑定数据
notifyDataSetChange()进行全局刷新时:
直接刷新所有item,会导致所有item进入回收池,不走mCacheViews直接RecyclerViewPool
notifyItemChanged进行局部刷新时:
mAttachedScrap
ArrayList
mChangeScrap
ArrayList
RecyclerView核心机制
pre/post-layout:当RecyclerView发生changed相关调用,比如删除或增加layout,会有一个动画,是通过预测性动画来实现的,changed发生是,RecyclerView会同时进行两个layout布局,一个是改变前,一个是改变后,通过对比来确定动画的起始和终止点。
比较特别的是,当某个item是change,此时这个item需要两个ViewHolder,一个老数据的holder渐隐动画,一个新数据的holder做出场动画。这样可以处理整个item的view都改变的情况。这个机制也导致了即使局部数据改变,change某个item时,依然会有闪烁动画。(可以通过关闭动画避免,或者调用notifyItemChanged(position, “payload”)进行局部刷新,不走预测性动画)
这时候mChangeScrap内存着的就是pre-layout中的layout
当进行pre-layout时,layout从mAttachedScrap和mChangeScrap中获取,而post-layout从pool和cache中获取