如何将android.support.v7.util.DiffUtil与RxJava、LiveData一起使用,而不生成



我当前的Android应用程序使用LiveData填充我的recyclerView。

有些用户有1000个项目要显示。

我还允许我的用户搜索/过滤回收器视图中的项目。

列表的初始显示很好。

然而,当用户开始搜索/过滤从1000到1或2个项目的列表时,用户体验确实变得非常差,UI在10秒内变得没有响应。

我的RecyclerView适配器使用android.support.v7.util.DiffUtil来管理列表项更改。

我尝试在我的活动onChange方法中使用RxJava在后台线程上执行diffing

Observable.just(newItems)
.doOnSubscribe(compositeDisposable::add)
.subscribeOn(Schedulers.io())
.switchMap(new Function<List<ItemUI>, ObservableSource<DiffUtil.DiffResult>>() {
@Override
public ObservableSource<DiffUtil.DiffResult> apply(final List<ItemUI> itemUIs) {
final DiffUtil.DiffResult diffResult = DiffUtil.calculateDiff(new GenericDiffUtilCallback<>(adapter.getCurrentItems(), newItems));
return Observable.just(diffResult);
}
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<DiffUtil.DiffResult>() {
@Override
public void accept(final DiffUtil.DiffResult diffResult) {
adapter.updateList(diffResult, articles);
}
});

My Adapter up[dateList方法类似于此

public void updateList(final DiffUtil.DiffResult diffResult, final List<ItemUI> newItems) {
this.items.clear();
this.items.addAll(newItems);
diffResult.dispatchUpdatesTo(this);
}

我仍然看到像这个这样的logcat消息

Choreographer: Skipped 200 frames!  The application may be doing too much work on its main thread.

我犯了什么错误,仍然看到跳过的帧?

是否可以区分大列表的更改,并且仍然具有响应UI?

理论上,发布的代码不应该在主线程上执行diff。

尝试以下操作:

Observable.just(newItems)
.observeOn(Schedulers.io())  // <------------------------------------
.map(new Function<List<ItemUI>, DiffUtil.DiffResult>() {
@Override
public DiffUtil.DiffResult apply(final List<ItemUI> itemUIs) {
return DiffUtil.calculateDiff(
new GenericDiffUtilCallback<>(
adapter.getCurrentItems(), itemUIs));
}
})
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(compositeDisposable::add) // <------------------------
.subscribe(new Consumer<DiffUtil.DiffResult>() {
@Override
public void accept(final DiffUtil.DiffResult diffResult) {
adapter.updateList(diffResult, articles);
}
});

你其实并不需要switchMap。此外,如果你真的想让dispose生效,你必须尽可能地将其向下移动,否则原始问题中的位置将不会对其下面的diff计算产生影响。

我还想检查一下你是否无意中遇到了线程问题,比如这个博客中描述的情况

编辑:

如果您有更改源,您可以使用switchMap,但也可以使用fromCallable

.switchMap(itemUIs ->  {
return Observable.fromCallable(() ->
DiffUtil.calculateDiff(new GenericDiffUtilCallback<>(
adapter.getCurrentItems(), itemUIs))
)
.subscribeOn(Schedulers.computation());
})

最新更新