它具体做了什么
-
当某个 item 滑出屏幕时,Recycler 会先尝试把对应的 ViewHolder 放进 mCachedViews(容量由你设置决定)。
-
以后如果又需要同一个 position(或启用 stableIds 后,同一个 id) ,会优先从这里取用:
- 命中时通常无需重新绑定(不触发 onBindViewHolder) ,只需位置复位 → 更平滑、少一次绑定开销。
-
如果本地缓存已满,被挤出的 ViewHolder 会被放入 RecycledViewPool(按 viewType 的“冷缓存”,再次用时要 rebind)。
和其他缓存的区别(速记)
-
Scrap(本帧临时) :同一轮布局中的“原地复用”,成本最低。
-
Cache(mCachedViews,你设置的这个) :本地热缓存,按 position/id 直接复用,常可免 rebind。
-
Pool(RecycledViewPool) :跨 RV 共享、按 viewType 分桶的冷缓存,再用时需 rebind。
作用与收益
-
减少白板感、减少 onBindViewHolder 调用,提升短距离来回滚动的流畅度。
-
对绑定成本较高(复杂布局/数据组装)的条目收益明显。
代价与误区
-
占用更多内存:缓存的每个 item 及其子 View 都会常驻(包括图片引用等)。
-
不是预加载:它不会提前创建新的 View,只是“多留几个刚离屏的”。
-
数据频繁变更时,这些缓存会被标记为需要重绑,不能保证永远免 onBind。
什么时候调、调多少
-
列表复杂但内存充裕:可设 4–8(甚至更高,视页面而定)。
-
图片密集/内存紧张页面(瀑布流/大图):保持 2–4 较稳妥。
-
结合:
-
setHasStableIds(true) 提升“同 id 免重绑”的命中率;
-
RecycledViewPool.setMaxRecycledViews(viewType, max) 调冷缓存;
-
LinearLayoutManager/嵌套 RV 配合 prefetch 做错峰绑定。
-
一条实践范式
recyclerView.setItemViewCacheSize(6) // 提升本地热缓存
recyclerView.recycledViewPool.apply {
setMaxRecycledViews(VT_BIG, 10) // 重型卡片冷缓存也拉高
setMaxRecycledViews(VT_SMALL, 15)
}
adapter.setHasStableIds(true) // 用稳定ID提高命中
一句话:setItemViewCacheSize 决定“离屏还留几个已绑定好的 ViewHolder 在手边”。调大能换取更顺滑的回滚体验,但要用内存做代价;配合稳定 ID、DiffUtil 与 RecycledViewPool,一起调,效果最佳。