• 浅谈RecyclerView的性能优化


    RecyclerView的性能优化

    在我们谈RecyclerView的性能优化之前,先让我们回顾一下RecyclerView的缓存机制。

    RecyclerView缓存机制

    众所周知,RecyclerView拥有四级缓存,它们分别是:

    • Scrap缓存:包括mAttachedScrap和mChangedScrap,又称屏内缓存,不参与滑动时的回收复用,只是用作临时保存的变量。
      • mAttachedScrap:只保存重新布局时从RecyclerView分离的item的无效、未移除、未更新的holder。
      • mChangedScrap:只会负责保存重新布局时发生变化的item的无效、未移除的holder。
    • CacheView缓存:mCachedViews又称离屏缓存,用于保存最新被移除(remove)的ViewHolder,已经和RecyclerView分离的视图,这一级的缓存是有容量限制的,默认最大数量为2。
    • ViewCacheExtension:mViewCacheExtension又称拓展缓存,为开发者预留的缓存池,开发者可以自己拓展回收池,一般不会用到。
    • RecycledViewPool:终极的回收缓存池,真正存放着被标识废弃(其他池都不愿意回收)的ViewHolder的缓存池。这里的ViewHolder是已经被抹除数据的,没有任何绑定的痕迹,需要重新绑定数据。

    RecyclerView的回收原理

    (1)如果是RecyclerView不滚动情况下缓存(比如删除item)、重新布局时。

    • 把屏幕上的ViewHolder与屏幕分离下来,存放到Scrap中,即发生改变的ViewHolder缓存到mChangedScrap中,不发生改变的ViewHolder存放到mAttachedScrap中。
    • 剩下ViewHolder会按照mCachedViews > RecycledViewPool的优先级缓存到mCachedViews或者RecycledViewPool中。

    (2)如果是RecyclerView滚动情况下缓存(比如滑动列表),在滑动时填充布局。

    • 先移除滑出屏幕的item,第一级缓存mCachedViews优先缓存这些ViewHolder。
    • 由于mCachedViews最大容量为2,当mCachedViews满了以后,会利用先进先出原则,把旧的ViewHolder存放到RecycledViewPool中后移除掉,腾出空间,再将新的ViewHolder添加到mCachedViews中。
    • 最后剩下的ViewHolder都会缓存到终极回收池RecycledViewPool中,它是根据itemType来缓存不同类型的ArrayList,最大容量为5。

    RecyclerView的复用原理

    当RecyclerView要拿一个复用的ViewHolder时:

    • 如果是预加载,则会先去mChangedScrap中精准查找(分别根据position和id)对应的ViewHolder。
    • 如果没有就再去mAttachedScrap和mCachedViews中精确查找(先position后id)是不是原来的ViewHolder。
    • 如果还没有,则最终去mRecyclerPool找,如果itemType类型匹配对应的ViewHolder,那么返回实例,让它重新绑定数据
    • 如果mRecyclerPool也没有返回ViewHolder才会调用createViewHolder()重新去创建一个。

    这里有几点需要注意:

    • 在mChangedScrap、mAttachedScrap、mCachedViews中拿到的ViewHolder都是精准匹配。
    • mAttachedScrap和mCachedViews没有发生变化,是直接使用的。
    • mChangedScrap由于发生了变化,mRecyclerPool由于数据已被抹去,所以都需要调用onBindViewHolder()重新绑定数据才能使用。

    缓存机制总结

    • RecyclerView最多可以缓存 N(屏幕最多可显示的item数【Scrap缓存】) + 2 (屏幕外的缓存【CacheView缓存】) + 5*M (M代表M个ViewType,缓存池的缓存【RecycledViewPool】)。
    • RecyclerView实际只有两层缓存可供使用和优化。因为Scrap缓存池不参与滚动的回收复用,所以CacheView缓存池被称为一级缓存,又因为ViewCacheExtension缓存池是给开发者定义的缓存池,一般不用到,所以RecycledViewPool缓存池被称为二级缓存。

    如果想深入了解RecyclerView缓存机制的同学,可以参考《RecyclerView的回收复用缓存机制详解》 这篇文章。

    性能优化方案

    根据上面我们对缓存机制的了解,我们可以简单得到以下几个大方向:

    • 1.提高ViewHolder的复用,减少ViewHolder的创建和数据绑定工作。【最重要】
    • 2.优化onBindViewHolder方法,减少ViewHolder绑定的时间。由于ViewHolder可能会进行多次绑定,所以在onBindViewHolder()尽量只做简单的工作。
    • 3.优化onCreateViewHolder方法,减少ViewHolder创建的时间。

    提高ViewHolder的复用

    1.多使用Scrap进行局部更新。