RecyclerView的四级缓存机制

RecyclerView的四级缓存机制是其高性能的核心,通过逐级复用视图(ViewHolder)减少创建和绑定开销。以下结合源码逻辑与工作流程图进行详细解析:


📊 ​四级缓存结构与工作流程​

flowchart TD subgraph 缓存回收 A[视图移出屏幕] --> B{"是否在屏幕内?"} B -->|是| C[存入mAttachedScrap] B -->|否| D{"是否最近移出?"} D -->|是| E[存入mCachedViews] D -->|否| F{"是否自定义缓存?"} F -->|是| G[存入ViewCacheExtension] F -->|否| H[存入RecycledViewPool] end subgraph 缓存复用 I[需要新视图] --> J{"位置是否匹配?"} J -->|是| K[从mCachedViews获取] J -->|否| L{"类型是否匹配?"} L -->|是| M[从RecycledViewPool获取] L -->|否| N[新建ViewHolder] K --> O[无需重新绑定数据] M --> P[需调用onBindViewHolder] end

🔍 ​各级缓存详解​

1. ​一级缓存:Scrap 缓存(mAttachedScrap / mChangedScrap)​​

  • ​作用​:临时存储屏幕内因布局更新(如滚动、局部刷新)而暂时分离的视图。

  • ​复用条件​:

    • mAttachedScrap:视图未发生数据变化,复用无需重新绑定数据。
    • mChangedScrap:数据已更新(如notifyItemChanged()),复用需重新绑定。
  • ​生命周期​:仅在布局过程中存在,完成后清空。

2. ​二级缓存:mCachedViews​

  • 作用 :存储最近移出屏幕的视图(默认容量2),保留完整数据和位置信息。
  • 复用条件 :新进入屏幕的项必须与原位置相同(例如快速反向滑动时),复用无需重新绑定数据。
  • 淘汰策略 :容量满时按FIFO(先进先出)移入RecycledViewPool。

3. ​三级缓存:ViewCacheExtension(可选)​​

  • 作用:开发者自定义缓存逻辑(如跨列表复用复杂视图),需手动管理创建和回收。
  • 典型场景:缓存特殊类型的视图(如地图控件),避免重复初始化开销。

4. ​四级缓存:RecycledViewPool​

  • 作用 :存储解绑数据 的视图,按viewType分类(每类默认容量5)。
  • 复用条件 :类型匹配即可复用,但需重新调用onBindViewHolder()绑定数据。
  • 共享机制 :多个RecyclerView可共用同一RecycledViewPool,减少内存占用。

⚙️ ​完整工作流程(结合源码逻辑)​​

  1. ​视图回收(移出屏幕)​​:

    • 屏幕内视图 → 存入mAttachedScrap(布局更新时)。
    • 屏幕外视图 → 优先存入mCachedViews(容量未满时) → 满则移入RecycledViewPool。
  2. ​视图复用(进入屏幕)​​:

    • 步骤1 :从mAttachedScrap查找位置匹配项(无需绑定)。
    • 步骤2 :从mCachedViews查找相同位置的视图(无需绑定)。
    • 步骤3 :从ViewCacheExtension获取自定义缓存(若有)。
    • 步骤4 :从RecycledViewPool获取同类型视图(需重新绑定数据)。
    • 步骤5 :若均无匹配,调用Adapter.onCreateViewHolder()创建新视图。

⚠️ ​关键问题与优化实践​

  1. ​数据错乱问题​:

    • 原因 :RecycledViewPool中的视图未清除旧数据,复用后未及时更新(如"五角星图标错误显示")。
    • 解决 :在onBindViewHolder()中重置视图状态,避免依赖历史数据。
  2. ​性能调优策略​:

    • 增大mCachedViews容量 :recyclerView.setItemViewCacheSize(10),提升快速滑动流畅度。
    • **共享RecycledViewPool**:多个列表复用同一池,减少内存碎片。
    • **使用DiffUtil**:局部更新数据,避免全局刷新(notifyDataSetChanged())。
  3. ​自定义缓存实践​:

    java 复制代码
    // 实现ViewCacheExtension缓存特定位置视图
    recyclerView.setViewCacheExtension(new RecyclerView.ViewCacheExtension() {
        @Override
        public View getViewForPositionAndType(RecyclerView.Recycler recycler, int position, int type) {
            if (position == 0) { // 缓存首项
                return recycler.getViewForPosition(0);
            }
            return null;
        }
    });

💎 ​总结​

RecyclerView的四级缓存通过位置优先 → 类型匹配 的复用策略,结合保留数据 → 解绑数据的层次设计,最大化平衡性能与内存效率。开发中应重点关注:

  1. 避免onBindViewHolder()中的耗时操作,确保滚动流畅。
  2. 对复杂视图使用setHasFixedSize(true)减少测量开销。
  3. 嵌套场景使用共享RecycledViewPool(如多Tab列表)。
相关推荐
千里马学框架3 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台3 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone3 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc3 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo3 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077003 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼3 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone3 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen3 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone3 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui