先来对比一下 :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/