搜狗站长平台打不开,怎么做网站淘宝转换工具,wordpress 前台上传文件,西宁网络推广公司RecyclerView的性能优化 在我们谈RecyclerView的性能优化之前#xff0c;先让我们回顾一下RecyclerView的缓存机制。 RecyclerView缓存机制
众所周知#xff0c;RecyclerView拥有四级缓存#xff0c;它们分别是#xff1a; Scrap缓存#xff1a;包括mAttachedScrap和mCha…RecyclerView的性能优化 在我们谈RecyclerView的性能优化之前先让我们回顾一下RecyclerView的缓存机制。 RecyclerView缓存机制
众所周知RecyclerView拥有四级缓存它们分别是 Scrap缓存包括mAttachedScrap和mChangedScrap又称屏内缓存不参与滑动时的回收复用只是用作临时保存的变量。 mAttachedScrap只保存重新布局时从RecyclerView分离的item的无效、未移除、未更新的holder。mChangedScrap只会负责保存重新布局时发生变化的item的无效、未移除的holder。 CacheView缓存mCachedViews又称离屏缓存用于保存最新被移除(remove)的ViewHolder已经和RecyclerView分离的视图这一级的缓存是有容量限制的默认最大数量为2。 ViewCacheExtensionmViewCacheExtension又称拓展缓存为开发者预留的缓存池开发者可以自己拓展回收池一般不会用到。 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进行局部更新。 (1) 使用notifyItemChange、notifyItemInserted、notifyItemMoved和notifyItemRemoved等方法替代notifyDataSetChanged方法。 (2) 使用notifyItemChanged(int position, Nullable Object payload)方法传入需要刷新的内容进行局部增量刷新。这个方法一般很少有人知道具体做法如下 首先在notify的时候在payload中传入需要刷新的数据一般使用Bundle作为数据的载体。 然后重写RecyclerView.Adapter的onBindViewHolder(NonNull RecyclerViewHolder holder, int position, NonNull ListObject payloads)方法 Override
public void onBindViewHolder(NonNull RecyclerViewHolder holder, int position, NonNull ListObject payloads) {if (CollectionUtils.isEmpty(payloads)) {Logger.e(正在进行全量刷新: position);onBindViewHolder(holder, position);return;}// payloads为非空的情况进行局部刷新//取出我们在getChangePayload方法返回的bundleBundle payload WidgetUtils.getChangePayload(payloads);if (payload null) {return;}Logger.e(正在进行增量刷新: position);for (String key : payload.keySet()) {if (KEY_SELECT_STATUS.equals(key)) {holder.checked(R.id.scb_select, payload.getBoolean(key));}}
}详细使用方法可参考XUI中的RecyclerView局部增量刷新 中的代码。 (3) 使用DiffUtil、SortedList进行局部增量刷新提高刷新效率。和上面讲的传入payload原理一样这两个是Android默认提供给我们使用的两个封装类。这里我以DiffUtil举例说明该如何使用。 首先需要实现DiffUtil.Callback的5个抽象方法具体可参考DiffUtilCallback.java然后调用DiffUtil.calculateDiff方法返回比较的结果DiffUtil.DiffResult。最后调用DiffUtil.DiffResult的dispatchUpdatesTo方法传入RecyclerView.Adapter进行数据刷新。
详细使用方法可参考XUI中的DiffUtil局部刷新 和 XUI中的SortedList自动数据排序刷新 中的代码。
2.合理设置RecyclerViewPool的大小。如果一屏的item较多那么RecyclerViewPool的大小就不能再使用默认的5可适度增大Pool池的大小。如果存在RecyclerView中嵌套RecyclerView的情况可以考虑复用RecyclerViewPool缓存池减少开销。
3.为RecyclerView设置setHasStableIds为true并同时重写RecyclerView.Adapter的getItemId方法来给每个Item一个唯一的ID提高缓存的复用率。
4.视情况使用setItemViewCacheSize(size)来加大CacheView缓存数目用空间换取时间提高流畅度。对于可能来回滑动的RecyclerView把CacheViews的缓存数量设置大一些可以省去ViewHolder绑定的时间加快布局显示。
5.当两个数据源大部分相似时使用swapAdapter代替setAdapter。这是因为setAdapter会直接清空RecyclerView上的所有缓存但是swapAdapter会将RecyclerView上的ViewHolder保存到pool中这样当数据源相似时就可以提高缓存的复用率。
优化onBindViewHolder方法
1.在onBindViewHolder方法中去除冗余的setOnItemClick等事件。因为直接在onBindViewHolder方法中创建匿名内部类的方式来实现setOnItemClick会导致在RecyclerView快速滑动时创建很多对象。应当把事件的绑定在ViewHolder创建的时候和对应的rootView进行绑定。
2.数据处理与视图绑定分离去除onBindViewHolder方法里面的耗时操作只做纯粹的数据绑定操作。当程序走到onBindViewHolder方法时数据应当是准备完备的禁止在onBindViewHolder方法里面进行数据获取的操作。
3.有大量图片时滚动时停止加载图片停止后再去加载图片。
4.对于固定尺寸的item可以使用setHasFixedSize避免requestLayout。
优化onCreateViewHolder方法
1.降低item的布局层级可以减少界面创建的渲染时间。
2.Prefetch预取。如果你使用的是嵌套的RecyclerView或者你自己写LayoutManager则需要自己实现Prefetch重写collectAdjacentPrefetchPositions方法。
其他
以上都是针对RecyclerView的缓存机制展开的优化方案其实还有几种方案可供参考。
1.取消不需要的item动画。具体的做法是
((SimpleItemAnimator) recyclerView.getItemAnimator()).setSupportsChangeAnimations(false);2.使用getExtraLayoutSpace为LayoutManager设置更多的预留空间。当RecyclerView的元素比较高一屏只能显示一个元素的时候第一次滑动到第二个元素会卡顿这个时候就需要预留的额外空间让RecyclerView预加载可重用的缓存。
最后
以上就是RecyclerView性能优化的全部内容俗话说百闻不如一见百见不如一干大家还是赶紧动手尝试着开始进行优化吧!RecyclerView的性能优化
需要更多的Android 性能优化实战可以扫码免费领取资料 《Android 性能优化实战篇》
目录 1. 腾讯Bugly—对字符串匹配算法的一点理解
2. 爱奇艺技术产品团队—干货|安卓APP崩溃捕获方案——xCrash
3. 字节跳动技术团队— 深入理解Gradle框架之一Plugin, Extension, buildSrc
4. 百度APP-Android H5首屏优化实践
5. 京东技术—任意URL跳转漏洞修复与JDK中getHost()方法之间的坑
6. 支付宝客户端架构解析Android 客户端启动速度优化之「垃圾回收」
7. 支付宝 App 构建优化解析通过安装包重排布优化 Android 端启动性能
8. 支付宝 App 构建优化解析Android 包大小极致压缩
9. 搜狐技术产品—深入理解Flutter多线程
10. 携程技术—从智行 Android 项目看组件化架构实践
11. 谷歌开发者—Flutter 您需要知道的知识点