RecyclerView 缓存复用机制详解
RecyclerView 是 Android 开发中用于展示列表数据的核心组件,其核心优势在于高效的视图复用机制。理解这一机制对于优化列表滑动性能、降低内存消耗至关重要。
一、核心概念与目的
RecyclerView 的设计初衷是回收其列表项视图以供重用。当一个列表项被移出屏幕后,它不会立即销毁,而是进入缓存池。当新的列表项需要显示时,优先从缓存中获取已有的 ViewHolder 对象进行数据绑定。
这种机制带来的主要收益包括:
- 避免重复创建视图:减少
onCreateViewHolder的调用次数。 - 避免重复查找控件:减少
findViewById等昂贵操作。 - 提升性能:改善滑动流畅度,降低 CPU 和功耗。
二、关键类协作
RecyclerView 构建动态列表主要依赖以下两个类的配合:
1. ViewHolder
ViewHolder 是一个包含列表项视图 (itemView) 的封装容器,也是缓存复用的主要载体。它持有子 View 引用,避免每次刷新都重新查找。
2. Adapter
Adapter 负责建立数据与视图的映射关系,核心方法包括:
onCreateViewHolder:创建并初始化 ViewHolder 及其关联视图,不填充数据。onBindViewHolder:提取数据,填充 ViewHolder 的视图内容。
为了减少这两个方法的回调频次,系统会积极缓存复用 ViewHolder 对象。优先级顺序如下:
- 最优情况:直接复用原有的 ViewHolder 对象(无需重建,无需绑定)。
- 次优情况:复用同类型 (
itemType) 的 ViewHolder 对象(需重新绑定数据)。 - 最后手段:创建新的 ViewHolder 对象并绑定数据。
三、Recycler 查找逻辑
真正负责执行查找工作的内部类是 Recycler。在 tryGetViewHolderForPositionByDeadline 方法中,Recycler 按照严格的优先级顺序尝试获取 ViewHolder:
public final class Recycler {
@Nullable
ViewHolder tryGetViewHolderForPositionByDeadline(int position,
boolean dryRun, long deadlineNs) {
// 0. 尝试从 mChangedScrap 中获取(处理动画场景)
if (mState.isPreLayout()) {
holder = getChangedScrapViewForPosition(position);
}
// 1.1 尝试根据 position 从 mAttachedScrap 或 mCachedViews 获取
(holder == ) {
holder = getScrapOrHiddenOrCachedHolderForPosition(position, dryRun);
}
(holder == && mAdapter.hasStableIds()) {
holder = getScrapOrCachedViewForId(mAdapter.getItemId(offsetPosition), type, dryRun);
}
(holder == && mViewCacheExtension != ) {
mViewCacheExtension.getViewForPositionAndType(, position, type);
(view != ) {
holder = getChildViewHolder(view);
}
}
(holder == ) {
holder = getRecycledViewPool().getRecycledView(type);
}
(holder == ) {
holder = mAdapter.createViewHolder(RecyclerView., type);
}
(!holder.isBound() || holder.needsUpdate() || holder.isInvalid()) {
bound = tryBindViewHolderByDeadline(holder, offsetPosition, position, deadlineNs);
}
holder;
}
}


