RecyclerView 的缓存机制是其高性能的核心,分为四级缓存,按优先级从高到低依次查找可复用的 ViewHolder。
四级缓存总览
| 级别 | 缓存对象 | 容量 | 作用范围 | 数据是否重置 |
|---|---|---|---|---|
| 一级 | mAttachedScrap/mChangedScrap | 无固定上限 | 屏幕内 | 否 |
| 二级 | mCachedViews | 默认2 | 刚滑出屏幕 | 否 |
| 三级 | mViewCacheExtension | 自定义 | 开发者控制 | 否 |
| 四级 | mRecyclerPool | 每种 type 默认5 | 缓存池 | 是 |
一级缓存:mAttachedScrap / mChangedScrap(屏幕内缓存)
触发场景
调用
notifyDataSetChanged()、notifyItemRangeChanged()等局部刷新方法时LayoutManager对 Item 进行重新布局时
特点
数据无需重新绑定:ViewHolder 的 position、数据都保持不变
直接从
mAttachedScrap中取出,不走onBindViewHolder()mChangedScrap用于处理notifyItemChanged()等变化场景
java
// 伪代码示意 if (holder = mAttachedScrap.get(position)) { // 直接复用,无需绑定 return holder; }二级缓存:mCachedViews(屏幕外缓存)
触发场景
Item刚滑出屏幕时,会被放入
mCachedViews用户快速滑回时,能立即复用
特点
默认容量为2(可通过
setItemViewCacheSize()调整)数据保持原样:ViewHolder 的 position 和数据不变
复用时无需调用
onBindViewHolder()超出容量时,按 FIFO 规则移入四级缓存(RecyclerPool)
java
// 设置二级缓存大小 recyclerView.setItemViewCacheSize(5);适用场景
左右滑动切换的 ViewPager2(内部基于 RecyclerView)
列表快速来回滑动
三级缓存:mViewCacheExtension(自定义缓存)
触发场景
开发者自行实现的缓存策略
系统默认不启用(返回 null)
特点
需要继承
RecyclerView.ViewCacheExtension并实现getViewForPositionAndType()极少使用,除非有极其特殊的缓存需求
java
// 几乎不会用到 RecyclerView.ViewCacheExtension extension = new RecyclerView.ViewCacheExtension() { @Override public View getViewForPositionAndType(Recycler recycler, int position, int viewType) { // 自定义逻辑,通常返回 null return null; } }; recyclerView.setViewCacheExtension(extension);四级缓存:mRecyclerPool(缓存池)
触发场景
mCachedViews满后,新滑出的 Item 会进入 Pool不同 RecyclerView 之间共享缓存时
特点
按
viewType分类存储,每种 type 默认容量为5数据会被重置:复用时必须调用
onBindViewHolder()可多个 RecyclerView 共享同一个 Pool
java
// 获取/设置缓存池 RecyclerView.RecycledViewPool pool = recyclerView.getRecycledViewPool(); pool.setMaxRecycledViews(TYPE_ITEM, 10); // 设置某类型的最大缓存数 // 多个 RecyclerView 共享缓存池(常见于嵌套 RecyclerView) recyclerView2.setRecycledViewPool(pool);缓存查找流程图
plain
尝试获取 ViewHolder │ ▼ ┌─────────────────────┐ │ 1. mAttachedScrap │ ──► 命中?直接返回(不绑定数据) │ / mChangedScrap │ └─────────────────────┘ │ 未命中 ▼ ┌─────────────────────┐ │ 2. mCachedViews │ ──► 命中?直接返回(不绑定数据) └─────────────────────┘ │ 未命中 ▼ ┌─────────────────────┐ │ 3. mViewCacheExt │ ──► 命中?直接返回(不绑定数据) └─────────────────────┘ │ 未命中 ▼ ┌─────────────────────┐ │ 4. mRecyclerPool │ ──► 命中?返回,但需调用 onBindViewHolder() └─────────────────────┘ │ 未命中 ▼ 创建新的 ViewHolder(onCreateViewHolder)实际开发建议
| 场景 | 建议 |
|---|---|
| 列表快速来回滑动 | 调大mCachedViews:setItemViewCacheSize(5) |
| 嵌套 RecyclerView | 共享RecycledViewPool,避免重复创建 |
| 多种 Item 类型 | 通过setMaxRecycledViews()调整各类型的 Pool 大小 |
| 超大图/视频 Item | 适当减小缓存,避免内存占用过高 |
| 预加载 | 配合GapWorker(RecyclerView 内部预取机制) |
一句话总结
一级保屏幕内、二级保刚滑出、三级自定义、四级兜底复用。
前三级不重新绑定数据,四级必须重新绑定。这就是 RecyclerView 比 ListView 流畅的根本原因。