字节跳动Android高级岗:说说RecyclerView的回收复用机制

是这样的,想请讲解下,字节跳动Android高级岗:说说RecyclerView的回收复用机制
最新回答
青澜饮舟

2026-10-30 15:03:37

RecyclerView的回收复用机制通过缓存ViewHolder对象实现,回收发生在itemView不可见时,复用发生在itemView可见时,核心逻辑围绕滑动事件触发,结合四重缓存结构优化性能。具体机制如下:

回收与复用的核心对象
  • 回收和复用的单位均为ViewHolder对象:RecyclerView将每个itemView封装为ViewHolder,缓存和复用的本质是对ViewHolder的存取操作。内部类Recycler通过ArrayList<ViewHolder>结构管理缓存,例如mScrap、mCachedViews等字段均基于此设计。

图:回收流程——不可见的itemView被封装为ViewHolder存入缓存池回收机制的实现细节
  • 触发时机:当itemView因滑动移出屏幕(从可见变为不可见)时,RecyclerView在onTouchEvent的move事件中触发回收逻辑。具体流程为:

    LayoutManager检测到itemView不可见;

    调用Recycler的recycleViewHolderInternal()方法;

    根据ViewHolder类型(如是否可复用、是否绑定数据)存入不同缓存层级。

  • 四重缓存结构:

    一级缓存(mCachedViews):默认容量为2,存储刚移出屏幕的ViewHolder,复用优先级最高。通过RecyclerView.setItemViewCacheSize()可调整容量。

    二级缓存(mScrap与mAttachedScrap):mAttachedScrap存储仍在RecyclerView中但需要重新布局的ViewHolder(如动画中的视图);mScrap存储临时移除的视图,需手动调用addScrapView()添加。

    三级缓存(mRecyclerPool):按viewType分类的缓存池,默认每个viewType容量为5。当一级/二级缓存不足时,从池中获取ViewHolder,需调用setRecycledViewPool()配置。

    四级缓存(重建ViewHolder):若所有缓存均无法满足需求,则通过Adapter.onCreateViewHolder()创建新实例。

复用机制的实现细节
  • 触发时机:当新itemView因滑动进入屏幕(从不可见变为可见)时,RecyclerView在布局阶段(dispatchLayoutStep2())触发复用逻辑。具体流程为:

    LayoutManager计算新itemView的位置和类型;

    调用Recycler.getRecycledView()按优先级搜索缓存:

    优先检查mCachedViews;

    若未命中,检查mScrap或mAttachedScrap;

    再未命中则从mRecyclerPool获取;

    最终调用Adapter.onBindViewHolder()绑定数据。

    若缓存均无可用ViewHolder,则执行Adapter.onCreateViewHolder()创建新实例。

图:复用流程——新itemView优先从缓存中获取ViewHolder并绑定数据关键源码逻辑
  • 回收入口:RecyclerView.onLayout() → dispatchLayout() → dispatchLayoutStep2()中调用LayoutManager.onLayoutChildren(),后者通过detachAndScrapAttachedViews()触发回收。
  • 复用入口:LayoutManager.fill()方法中调用getViewForPosition(),内部通过Recycler.getRecycledView()实现缓存搜索。
性能优化意义
  • 减少内存分配:复用ViewHolder避免频繁创建视图对象,降低内存抖动和GC压力。
  • 提升滑动流畅度:缓存机制减少inflate布局和findViewById操作,缩短帧渲染时间。
  • 灵活扩展性:通过LayoutManager和Adapter的解耦设计,支持自定义布局和复用策略(如网格、瀑布流等)。
开发者注意事项
  • 避免内存泄漏:在ViewHolder中持有Activity或Context引用时需使用弱引用。
  • 合理配置缓存大小:根据列表复杂度调整mCachedViews和mRecyclerPool容量,平衡内存占用与复用效率。
  • 重写onFailedToRecycleView():当ViewHolder因特殊状态(如正在动画)无法回收时,可在此方法中处理逻辑。