源码分析
RecyclerView extends ViewGroup
缓存复用部分以onCreateViewHolder()和onBindViewHolder()方法作为入口点、重点
onTouchEvent()// 滑动事件,入口点
scrollByInternal()
scrollStep()
scrollHorizontallyBy()|scrollVerticallyBy()-->mLayout(GridLayoutManager extends LinearLayoutManager)-->LinearLayoutManager
scrollBy()-->consumed 消费了得滑动距离
fill()// 关键方法
layoutChunk()-->View view = layoutState.next(recycler);// 缓存复用
measureChildWithMargins()// 测量计算
getItemDecorInsetsForChild()// 获取分割线参数
getItemOffsets()// 默认为0
layoutDecoratedWithMargins()// 布局定位
next()-->final View view = recycler.getViewForPosition(mCurrentPosition);
getViewForPosition()
tryGetViewHolderForPositionByDeadline()// 关键代码,主要得复用代码
getChangedScrapViewForPosition()-->mChangedScrap(position & StableId)//一级缓存
getScrapOrHiddenOrCachedHolderForPosition()--> mAttachedScrap mCachedViews position// 二级缓存
getScrapOrCachedViewForId()--> mAttachedScrap mCachedViews StableId
mViewCacheExtension.getViewForPositionAndType()// 三级缓存,自定义复用,缓存需要自己实现,一般用不到
getRecycledViewPool()// 四级缓存,从缓存池获取
createViewHolder()// 以上步骤一直没拿到ViewHolder,就需要创建ViewHolder对象
tryBindViewHolderByDeadline()-->mAdapter.bindViewHolder()
onBindViewHolder()// 处理数据得绑定
recycleByLayoutState()// 通过偏移量,部分缓存
recycleViewsFromEnd() | recycleViewsFromStart()// 上下回收
recycleChildren()
removeAndRecycleViewAt()-->recycler.recycleView(view)
recycleViewHolderInternal()// 缓存处理关键代码
if (cachedViewSize >= DEFAULT_CACHE_SIZE) {
recycleCachedViewAt()// mCachedViews满了
}
mCachedViews.add()// 存入mCachedViews
addViewHolderToRecycledViewPool()// 存入Pool
getRecycledViewPool().putRecycledView(holder);
getRecycledViewPool()
putRecycledView()
scrap.getItemViewType();
scrap.resetInternal();
scrapHeap.add(scrap);// mMaxScrap
dispatchNestedScroll()
pullGlows()// 处理边缘绘制效果
onMeasure()和onLayout()放在dispatchLayoutStep2()里面
onDraw()-->super.onDraw(c);// View
4级复用,缓存:一个Item容器,ViewHolder
RecyclerView绘制
- 好伴侣:详解DiffUtil
- 通讯录吸顶
- 探探效果:上下左右滑动事件,自定义LayoutManager
- 自定义分割线ItemDecoration
- StableId用于解决动画刷新闪烁问题
- 图片为什么会显示错乱?
RecyclerView比ListView优秀,更加灵活,模块化,解耦性好
布局LayoutManger
回收复用Recycler
分割线DividerItemDecoration
ArrayList<ViewHolder> mCachedViews // DEFAULT_CACHE_SIZE = 2
ArrayList<ViewHolder> scrapHeap // DEFAULT_MAX_SCRAP = 5
SparseArray<ScrapData> mScrap// Pool缓存池类似于HashMap,Array(ViewType)+ArrayList(ViewHolder)
mCachedViews和Pool得大小可以修改:setViewCacheSize()和setMaxRecycledViews()方法
mCachedViews缓存的内容包含数据,不需要调用onCreateViewHolder()和onBindViewHolder()方法
从缓存池Pool中复用:需要调用onBindViewHolder()方法
dispatchLayoutStep1()-->addToPreLayout() // 处理动画,动画前布局,例如删除Item后预布局
dispatchLayoutStep2()// 缓存复用
onLayoutChildren()
detachAndScrapAttachedViews(recycler)
scrapOrRecycleView()
recycler.recycleViewHolderInternal(viewHolder);
recycler.scrapView(view);
mAttachedScrap.add(holder);
mChangedScrap.add(holder);
dispatchLayoutStep3()-->addToPostLayout() // 处理动画,动画后布局
三个方法通过状态管理,只执行一次
查看控件源码思路:
- 构造函数:初始化
- 绘制流程:onMeasure() onLayout() onDraw()
- 数据处理
RecyclerView复用:四级缓存
- mChangedScrap与mAttachedScrap用来缓存还在屏幕内得ViewHolder
屏幕内缓存主要考虑的是性能问题;
mChangedScrap用于动画处理;
mAttachedScrap用于局部刷新。 - mCachedViews用来缓存移除屏幕之外得ViewHolder
- mViewCacheExtension这个得创建和缓存完全由开发者自己控制,系统未往这里添加数据
- RecycledViewPool ViewHolder缓存池