RecyclerView源码学习

本文详细剖析了RecyclerView的源码,重点关注onCreateViewHolder()和onBindViewHolder()方法在缓存复用中的作用。讲解了4级复用机制,包括ViewHolder的使用,以及mChangedScrap、mAttachedScrap、mCachedViews和RecycledViewPool在性能优化中的角色。此外,还探讨了自定义LayoutManager、DiffUtil、吸顶效果等高级用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

源码分析
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() // 处理动画,动画后布局

三个方法通过状态管理,只执行一次

查看控件源码思路:
  1. 构造函数:初始化
  2. 绘制流程:onMeasure() onLayout() onDraw()
  3. 数据处理
RecyclerView复用:四级缓存
  1. mChangedScrap与mAttachedScrap用来缓存还在屏幕内得ViewHolder
    屏幕内缓存主要考虑的是性能问题;
    mChangedScrap用于动画处理;
    mAttachedScrap用于局部刷新。
  2. mCachedViews用来缓存移除屏幕之外得ViewHolder
  3. mViewCacheExtension这个得创建和缓存完全由开发者自己控制,系统未往这里添加数据
  4. RecycledViewPool ViewHolder缓存池
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小山研磨代码

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值