← 返回目录01.01.07

RecyclerView四级缓存

部分 01 移动开发章节 Android基础 07/55创建 2026-10-19更新 2026-10-19阅读 –

RecyclerView四级缓存 ​

四级分别挡在新建前面 ​

列表滚动时,离开屏幕的 ViewHolder 不会马上丢掉。Recycler.tryGetViewHolderForPositionByDeadline 按固定顺序找一块能用的,四级都没有才执行 onCreateViewHolder。

  • Scrap:mAttachedScrap、mChangedScrap。没有固定格数,这次 layout 卸下多少就放多少。
  • CachedViews:mCachedViews,DEFAULT_CACHE_SIZE = 2。刚滑出屏幕的 holder 留在这里,position 和绑定都还在。
  • ViewCacheExtension:默认 null,格数是 0。自己实现 getViewForPositionAndType 之后,这一级才有东西。
  • RecycledViewPool:按 viewType 分桶,DEFAULT_MAX_SCRAP = 5。每种类型最多 5 个,拿出来要重新绑定。

一块 ViewHolder 的去向 ​

下面这块叫 A 的 ViewHolder,从还在屏幕上,到滑出屏幕,再到被同类型的新一行拿去绑定。

01 · Scrap

layout 开始时,还挂在 RecyclerView 上的 ViewHolder 被放进 mAttachedScrap。同一次 layout 又要这个 position,就从 scrap 拿回来。position 对得上、数据也没变,就不再执行 onBindViewHolder。mChangedScrap 只在预布局里用:notifyItemChanged 之后、动画开始前,变过的 holder 进这里。

02 · CachedViews

A 滑出屏幕,仍然有效,就进 mCachedViews。默认只留 2 个,setItemViewCacheSize 可以改。这里还记着原来的 position 和已经绑定的数据。马上滑回来,命中的是同一格,不执行 onBindViewHolder。

03 · Extension

屏幕上要的是一个新 position,scrap 和 CachedViews 里都没有它。Recycler 接着问 mViewCacheExtension.getViewForPositionAndType。这个扩展默认是 null,这一级什么都不返回。缓存满了之后,最旧的 holder 会被解绑送进池里,但送进池之前并不经过这一级。

04 · RecycledViewPool

A 被解绑后放进 RecycledViewPool,按 viewType 分桶,每类默认最多 5 个。进池时会走到 onViewRecycled,原来的绑定清掉。之后同类型的一项从池里拿走 A,省掉的是 onCreateViewHolder,onBindViewHolder 还是要执行。几个 RecyclerView 可以用 setRecycledViewPool 共用一个池。

05 · 新建

四级都没有,才执行 onCreateViewHolder 造一块新的,再执行 onBindViewHolder。新建是最贵的一步,前面每一级都是在避开它。

图 · 01.01.07STEP 00 / 04
SCRAP—A
CACHE2
EXT0
POOL5
A 在 AttachedScrap。同一次 layout 按 position 拿回,不重新绑定。
Java
// tryGetViewHolderForPositionByDeadline 的查找顺序
holder = attachedScrap or changedScrap;
if (holder == null) holder = cachedViews;          // DEFAULT_CACHE_SIZE = 2
if (holder == null && extension != null)
    view = extension.getViewForPositionAndType(recycler, position, type);
if (holder == null) holder = pool.getRecycledView(viewType); // 每类 DEFAULT_MAX_SCRAP = 5
if (holder == null) holder = adapter.createViewHolder(parent, type);
if (!holder.isBound()) adapter.onBindViewHolder(holder, position);

命中之后还要不要绑定 ​

  • Scrap、CachedViews:按原来的 position 命中,数据还在,跳过 onBindViewHolder。
  • RecycledViewPool:只认 viewType,不认 position。跳过的是 onCreateViewHolder,绑定要重新执行。
  • ViewCacheExtension:返回什么由自己决定。没有实现时,这一级等于不存在。