android - 当滚动太远时,如何防止 RecyclerView 为每个中间子级运行 onBindViewHolder
问题描述
我有一个RecyclerView作为日历,每个视图都是一天。
(占据屏幕的全宽和全高)
.----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------.
| .--------------. | | .--------------. | | .--------------. | | .--------------. | | .--------------. | | .--------------. | | .--------------. |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | (1) | | | | (2) | | | | (3) | | | | (4) | | | | (5) | | | | (...) | | | | (n) | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| '--------------' | | '--------------' | | '--------------' | | '--------------' | | '--------------' | | '--------------' | | '--------------' |
'----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------'
问题:
问题是,当用户试图滚动到未来非常遥远的日期时,即向前移动 40 天,onBindViewHolder
会为中间的所有 39 个孩子运行,这会浪费资源,因为滚动太快了,甚至没有人知道在那卷轴中每一天都包含什么。
因此,最后一天需要一些时间才能显示内容,因为主线程正忙于绘制所有中间天,除非用户手动滚动到它们,否则这些天将永远不可见。
需要什么:
我怎样才能防止 RecyclerView疯狂地加载所有这些中间的日子,而此时我所需要的只是用户结束的那一天。
.----------------. .----------------. .----------------. .----------------. .----------------. .----------------. .----------------.
| .--------------. | | .--------------. | | .--------------. | | .--------------. | | .--------------. | | .--------------. | | .--------------. |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | | | | | | | | | | | | | | | | | | | | | | | | | | |
| | (1) | | | | (2) | | | | (3) | | | | (4) | | | | (5) | | | | (...) | | | | (n) | |
| | LOAD | | | | DONT | | | | DONT | | | | DONT | | | | DONT | | | | DONT | | | | LOAD | |
| '--------------' | | '--------------' | | '--------------' | | '--------------' | | '--------------' | | '--------------' | | '--------------' |
'----------------' '----------------' '----------------' '----------------' '----------------' '----------------' '----------------'
(请不要告诉我使用scrollToPosition
,smoothScrollToPosition
因为删除动画不是一个选项)
谢谢
解决方案
你可以修改你的Adapter
类来检查平滑滚动的状态:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(recyclerView.getLayoutManager().isSmoothScrolling()){
// make viewholder into a "blank" here
return;
}
// regular binding
}
请注意,它有点粗略 - 应该ViewHolder
在滚动期间保持空白,否则它将显示无效天数。
这就像它得到的一样优雅(和简单),因为SmoothScroller
它实际上非常原始 - 它只是一直滚动直到找到目标视图,所以没有回调来知道何时已经布置了具有目标位置的视口。
绑定滚动“目标”时,您需要重新验证可见持有人。
ViewHolder
只有当您的 s 具有不变的统一大小并且您向适配器提供 smoothScroll 目标时,更完美的解决方案才能工作:
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
if(recyclerView.getLayoutManager().isSmoothScrolling()){
// scrollTarget is current smoothScroll target position
int diff = Math.abs(position - scrollTarget);
// viewHolderHeight is taken/cached from any viewHolder that was laid out previously
if(diff * viewHolderHeight > recyclerView.getHeight()){
// make viewholder into a "blank" here
return;
}
// still smoothscrolling, but viewholder will be visible when scroll ends
}
// regular binding
}
推荐阅读
- apache-spark - 工具抱怨使用 Glow pipe 变压器时不存在 contig
- c# - 来自 Json 的 Jquery 自动完成值
- javascript - 用 2 个日期在 javascript 中对 json 数据进行排序
- sql - 点和多边形之间的 STDistance 始终返回 0,即使它们相距数英里
- python - 在 Python 的 @classmethod 装饰器中使用 setattr 好不好
- selenium - Selenium 请求返回错误 400 - 错误请求
- mysql - Mysql:使用来自不同表/列的值更新 json 列
- elasticsearch - Elasticsearch 最新文章查询一组 id
- memory-management - 主存访问时间包括什么?
- python - 使用 Pywinauto 选择 Combobox 项