总览:谁跟谁配合(数据 → 视图 → 交互)
scss
数据源 → Adapter(差分/稳定ID/多类型) → ViewHolder(itemView)
↑ ↓
DiffUtil/AsyncListDiffer Recycler(回收/复用)
↑ ↓
RecyclerView(滚动/触摸/测量/调度) ← LayoutManager(布局/回收的大脑)
│ │
ItemDecoration ItemAnimator
│
RecycledViewPool(跨列表共享)
↑ ↑
SnapHelper/ItemTouchHelper/ConcatAdapter/Paging3(增强与组合)
1) RecyclerView(容器/调度中心)
职责
-
处理触摸与滚动(NestedScrolling、fling、OverScroll/EdgeEffect)。
-
驱动测量/布局 ,把"摆放与回收"职责交给 LayoutManager。
-
维护多级缓存与回收(与 Recycler/Pool 协作)。
-
驱动动画 (与 ItemAnimator 协作)与 装饰绘制(ItemDecoration)。
-
监听数据集变化(AdapterDataObserver)并触发 relayout/动画。
高频参数/技巧
- setHasFixedSize(true):子项尺寸稳定时减少 requestLayout。
- setItemViewCacheSize(n):增大临时缓存,减少 rebind(注意内存占用)。
- setRecycledViewPool(sharedPool):多个 RecyclerView 共享池。
- suppressLayout(true):批量操作期间暂缓布局(谨慎使用)。
2) LayoutManager(布局与回收的大脑)
职责
-
决定怎么摆放(线性/网格/瀑布/自定义)。
-
决定怎么回收(可见窗口外的 item 何时丢回缓存/池)。
-
处理滚动(水平/垂直偏移,边界、平滑滚动 SmoothScroller)。
-
支持预测性动画(pre-layout 阶段,新增/删除的过渡)。
内置
-
LinearLayoutManager:列表/横向轮播。
-
GridLayoutManager:网格,SpanSizeLookup 做跨列。
-
StaggeredGridLayoutManager:瀑布(注意 item 高度不等与回收复杂度)。
实战
- 嵌套列表(RecyclerView inside RecyclerView)用 setInitialPrefetchItemCount (Linear/GridLayoutManager)提高预取体验。
- 自定义 LM 需实现:测量、onLayoutChildren、scrollBy、canScroll*、generateDefaultLayoutParams、回收策略。
3) Adapter(把数据变成 ViewHolder)
职责
-
onCreateViewHolder:创建 ViewHolder(只做昂贵的一次性工作)。
-
onBindViewHolder(holder, position, payloads):绑定数据(增量更新请用 payloads)。
-
getItemViewType:返回稳定的类型编号(多类型列表的关键)。
-
(可选)setHasStableIds(true) + getItemId:稳定 ID有助于动画/复用。
实践要点
- 少用 notifyDataSetChanged() ;优先 DiffUtil/ListAdapter(见 §8)。
- 合理使用 payload 差量绑定 降低 rebind 成本。
- getBindingAdapterPosition() 与 getAbsoluteAdapterPosition() 区分清楚(ConcatAdapter 下尤为重要)。
4) ViewHolder(持有 itemView 的轻量控制器)
职责
-
缓存 itemView 子控件引用(避免频繁 findViewById)。
-
维护位置信息/类型、itemId、选择/激活状态等。
-
可临时 setIsRecyclable(false)(谨慎:会影响回收)。
最佳实践
- 在 onCreateViewHolder 完成一次性查找与监听器设置;在 onBind 只改数据与状态。
- 使用 ViewBinding/Databinding 简化持有与绑定。
5) Recycler / 四级缓存(回收与复用的流水线)
缓存层级(命中从快到慢)
-
Attached Scrap / Changed Scrap:本次布局中临时"借出"的可复用视图。
-
CachedViews:setItemViewCacheSize(n) 控制的内存缓存(不回池、带绑定状态)。
-
ViewCacheExtension:自定义扩展(少见)。
-
RecycledViewPool :按 viewType 分类的跨列表共享池(只存壳,不带数据绑定)。
关键点
- 复用命中高 → 绑定少 → 卡顿低。
- 未命中 → onCreateViewHolder 成本高;命中但需 onBind 成本中。
6) RecycledViewPool(跨列表共享复用池)
职责
-
在多个 RecyclerView 间按 viewType 共享 ViewHolder 实例。
-
setMaxRecycledViews(viewType, count):为热点类型预热容量。
-
getRecycledView / putRecycledView:取/放对象壳(不含数据)。
实战
- 首页多 Tab/多列表共享池显著减少创建抖动。
- 不同页面 type 编码要稳定(避免"拿错类型"导致重新创建)。
7) ItemDecoration(分割线/间距/吸顶/引导线)
回调
-
getItemOffsets:为每个 item 预留边距。
-
onDraw:在 item 下方绘制(背景层)。
-
onDrawOver:在 item 上方绘制(前景层,吸顶/遮罩)。
技巧
- 吸顶(sticky header)常在 onDrawOver 里计算当前组首并绘制。
- 多个 Decor 可叠加;注意过度绘制 与clipToPadding 的影响。
8) ItemAnimator(新增/删除/移动/改变动画)
默认:DefaultItemAnimator(基于 SimpleItemAnimator)。
常用设置
- ((SimpleItemAnimator) rv.getItemAnimator()).setSupportsChangeAnimations(false):关闭 change 动画,可避免 payload 小改也出现"闪烁/重绘"。
- 使用 稳定 ID 或 DiffUtil,让增删移有自然动画。
9) DiffUtil / AsyncListDiffer / ListAdapter(高效数据差分)
职责
-
计算新旧列表差异(可在后台线程),自动派发 notifyItem*,驱动动画。
-
ItemCallback.areItemsTheSame(身份 )/areContentsTheSame(内容 )/getChangePayload(增量字段)。
选择
-
ListAdapter:最省心(内部用 AsyncListDiffer)。
-
或手动用 AsyncListDiffer(适配已存在的 Adapter 结构)。
实践
- areItemsTheSame 用稳定唯一 ID。
- payload 返回"变更字段",让 onBind(holder, payloads) 局部刷新。
10) 增强配件:SnapHelper / ItemTouchHelper / ConcatAdapter / Paging3
- SnapHelper:对齐吸附(居中/页对页)。常用于 Banner/轮播+分页指示器。
- ItemTouchHelper:拖拽/滑动删除(自带阴影/位移动画),结合 DiffUtil 同步数据。
- ConcatAdapter:多个子 Adapter 拼接为一个列表;搭配 "头/尾/多模块"特性。
- Paging3:分页加载(内含 DiffUtil、占位符、RemoteMediator),与 ListAdapter/Flow 协作良好。
11) 关键时序与名词(易混点一次说清)
- pre-layout vs post-layout :预测性动画阶段会让 getLayoutPosition() 与 getAdapterPosition() 不同;业务中常用 getBindingAdapterPosition()。
- predictive animations:LayoutManager 可利用 pre-layout 构建进/出场动画(删除项仍暂时存在于"预测布局")。
- NestedScrolling:与 AppBarLayout/CoordinatorLayout 配合时注意 isNestedScrollingEnabled 与 AppBarLayout 的滚动冲突。
12) 性能清单(落地就提速)
- 预取:Linear/GridLayoutManager.setInitialPrefetchItemCount(k)(嵌套 RV 场景);
- 缓存:适度调大 setItemViewCacheSize;热点类型用共享 RecycledViewPool;
- 绑定减负 :耗时计算提前到 diff/后台;图片等异步加载要复用/取消(防错位);
- payload 局部刷:细粒度刷新避免整行重绑;
- 稳定 ID + Diff:更准确的动画与复用;
- 禁用不必要动画:supportsChangeAnimations(false);
- 避免频繁 notifyDataSetChanged() :改用差分或精准的 notify;
- 固定尺寸:setHasFixedSize(true);必要时 setItemAnimator(null) 保极致流畅。
13) 常见坑
- getItemViewType 不稳定 → 复用错乱/动画异常。确保同一数据行类型编号恒定。
- 在 onBind 里 setOnClickListener 每次 new → 额外对象分配;建议在 onCreate 设置一次,在 onBind 更新回调数据。
- setIsRecyclable(false) 滥用 → 池子命中率下降、内存飙升;只在短时动画/过渡必要时使用。
- 并发修改列表 → 与 DiffUtil 结果不一致;列表更新后再 submitList,避免共享引用被改。
- 大图/GPU 过度绘制 → ItemDecoration/背景叠加导致掉帧;用 Debug GPU Overdraw 检查。
一句话收束
把 LayoutManager 当成"布局 + 回收的司令部",Adapter/ViewHolder 当"数据→视图转换器",Recycler/Pool 当"复用流水线",再用 DiffUtil/ListAdapter 管理数据变化,ItemDecoration/Animator 管视觉,Snap/Touch/Concat/Paging 做增强。按上面的性能清单调参,你的 RecyclerView 在复杂业务里也能又快又稳。