RecyclerView 缓存机制
一、四级缓存体系
1. Scrap 缓存(临时缓存)
位置:
mAttachedScrap
和mChangedScrap
作用:
存储当前屏幕可见但被标记为移除的 ViewHolder
用于局部刷新(如
notifyItemChanged()
)
特点:
生命周期短(仅在一次布局过程中有效)
不需要重新绑定数据(
onBindViewHolder
不被调用)按位置索引存储
2. CacheViews(一级缓存)
位置:
mCachedViews
(默认大小 = 2)作用:
存储刚刚滚出屏幕的 ViewHolder
支持快速反向滚动恢复
特点:
按位置索引存储
不需要重新绑定数据
当新项加入时,最老的项会被移到 RecycledViewPool
3. ViewCacheExtension(二级缓存 - 自定义)
开发者扩展层:
public abstract static class ViewCacheExtension {public abstract View getViewForPositionAndType(Recycler recycler, int position, int type); }
作用:允许开发者实现自定义缓存逻辑
使用场景:
缓存特定位置的视图(如固定头部)
预加载复杂视图
注意:官方建议谨慎使用,大多数场景无需实现
4. RecycledViewPool(三级缓存)
位置:
mRecyclerPool
作用:
存储不同类型(viewType)的 ViewHolder 池
支持跨位置复用
特点:
按 viewType 分类存储(
SparseArray<ScrapData>
)需要重新绑定数据(会调用
onBindViewHolder
)默认每个类型缓存 5 个 ViewHolder
可全局共享(多个 RecyclerView 共用)
二、缓存获取优先级
当需要新视图时,RecyclerView 按以下顺序查询:
三、缓存生命周期详解
四、性能优化策略
1. 调整缓存大小
// 扩大一级缓存(默认2)
recyclerView.itemViewCacheSize = 10// 扩大回收池缓存(默认每个类型5个)
recyclerView.recycledViewPool.setMaxRecycledViews(viewType, 15)
2. 共享回收池(多列表优化)
// 创建共享池
val sharedPool = RecyclerView.RecycledViewPool()// 多个RecyclerView共享
recyclerView1.recycledViewPool = sharedPool
recyclerView2.recycledViewPool = sharedPool
3. 预加载机制
// 启用Item预取(Android 5.0+)
recyclerView.layoutManager?.isItemPrefetchEnabled = true// 设置预取数量
(recyclerView.layoutManager as LinearLayoutManager).initialPrefetchItemCount = 10
4. 优化ViewHolder创建
// 使用ViewStub延迟加载复杂布局
public class ComplexViewHolder extends RecyclerView.ViewHolder {private ViewStub stub;private View inflatedView;public ComplexViewHolder(View itemView) {super(itemView);stub = itemView.findViewById(R.id.complex_view_stub);}public void bind(boolean showComplex) {if (showComplex && inflatedView == null) {inflatedView = stub.inflate();}}
}
5. 监控缓存命中率
// 添加调试监听器
recyclerView.addOnChildAttachStateChangeListener(object : RecyclerView.OnChildAttachStateChangeListener {override fun onChildViewAttachedToWindow(view: View) {val holder = recyclerView.getChildViewHolder(view)when {holder.isRecyclable -> println("从缓存池复用")holder.isAttachedToTransitionOverlay -> println("从CacheViews复用")holder.isTmpDetached -> println("从Scrap复用")else -> println("全新创建")}}
})
五、缓存机制与DiffUtil的协同
六、最佳实践总结
合理设置缓存大小:
小列表(<50项):默认值足够
中大型列表:增大 itemViewCacheSize(5-15)
超长列表:增大 RecycledViewPool(10-20)
优化ViewHolder:
避免复杂布局嵌套
使用 ConstraintLayout 减少层级
耗时操作放在
onViewRecycled
释放