Recycler View 性能优化 (你必须知道的几点)

tech2024-04-12  71

先来对比一下 :ListView 与 RecyclerView

ViewHolder

基本原理 :使不使用 ViewHolder 都在复用 convertView ,

区别,是 findViewById 的性能节省。

ListView 缓存机制

Active View

在 Active View 中的item ,在滑动过程中,

listView 自动帮我们复用了,不会再走getView()方法

凡是调用了 getView() 视图都需要重新绑定。

Scrap View

Scrap View 中的数据都是“脏”的,都需要走getView() 方法

RecyclerView 缓存机制

四层缓存

前两层,Scrap 和 Cache 数据都是干净的,都可以拿来直接用。
第三层,ViewCacheExtension 是用户自定义的缓存策略
第四层,RecycledViewPool 数据时‘脏’ ,不走 onCreateViewHolder,但是需要重新绑定会走 onBindViewHolder 方法

RecyclerView 可能不知道的 性能优化策略

1、不要将 view 的 setOnClickListener(new View.OnClickListener()) 写在 OnBindView中,这样会频繁创建,尽量写在 onCreateViewHolder 中(但是处理逻辑就会有些麻烦 if/else, switch等 )

2、LinearLayoutManager.setInitialPrefetchItemCount() 预加载的数量,避免一些交复杂的布局,突然滑入屏幕显示的时候出现问题()

横向列表初次显示时可见的 Item 个数

PS :只有 LinearLayoutManager 有这个 API;

​ 只有嵌套在内部的 RecyclerView 才会生效

3、RecyclerView.setHasFixedSize(); (在recyclerView 数据变化 但是大小 不变的情况下,可以使用)

作用是:mHasFixedSize 为 true 时,回重新摆放 变化的 childLayout,不重新摆放所有布局(走 requestLayout方法)

void triggerUpdateProcessor() { if (POST_UPDATES_ON_ANIMATION && mHasFixedSize && mIsAttached) { ViewCompat.postOnAnimation(RecyclerView.this, mUpdateChildViewsRunnable); } else { mAdapterUpdateDuringMeasure = true; requestLayout(); } }

4、RecycledViewPool 缓存池 (根据 viewType 进行缓存)

比如:下面多列表的情况,可能多个 Rv 使用了相同的 viewType , 那么他们就可以 共享 缓存池

看下源码注释

RecycledViewPool lets you share Views between multiple RecyclerViews.

If you want to recycle views across RecyclerViews, create an instance of RecycledViewPool and use {@link RecyclerView#setRecycledViewPool(RecycledViewPool)}.

RecyclerView automatically creates a pool for itself if you don’t provide one.

大概意思:

RecycledViewPool使您可以在多个RecyclerView之间共享视图。

如果要在RecyclerViews中回收视图,请创建RecycledViewPool实例,然后使用{@link RecyclerView#setRecycledViewPool(RecycledViewPool)}。

如果您不提供一个池,RecyclerView会自动为其自动创建一个池。

如何使用:

开启这一项支持

需要注意的是,如果你使用的LayoutManager是LinearLayoutManager或其子类(如GridLayoutManager),需要手动开启这个特性: layout.setRecycleChildrenOnDetach(true)

DiffUtil 增量更新(提升列表性能)

DiffUtil .Callback (这是一个,给系统看的 callback,用于计算 diff 的 )
一共有5个方法:

下面 3 个方法 的返回值关系,以及执行顺序是

可以不实现 getChangePayload 方法,但是这样就不能看到RV 的增量更新了

如何 在adapter 中使用 :

这时候 发现 getChangePayload 中 返回的 payload 并没有被使用,在 adapter 中有一个 带 payloads 参数的 onBindViewHolder 重载方法, 他做的事就是 局部绑定 。

@Override public void onBindViewHolder(@NonNull DemoViewHolder holder, int position, @NonNull List<Object> payloads) { super.onBindViewHolder(holder, position, payloads); }

DiffUtil 的效率

在列表很大的时候计算 Diff ,计算可能会导致掉帧(>60ms)。
google 的推荐方法是 在列表很大的时候 【异步计算】 Diff

为什么 ItemDecoration 可以绘制分隔线?

ItemDecoration 还能做什么事情?

分割线 请自行脑补。。。

高亮

将item 进行分组

关于 RecyclerView 更多的扩展

可以看一下这个网址:

https://advancedrecyclerview.h6ah4i.com/swipeable/tutorial/

最新回复(0)