如何将 android.support.v7.util.DiffUtil 与 RxJava、LiveData 一起使用而不生成跳过的 ### 帧

How to employ android.support.v7.util.DiffUtil with RxJava, LiveData and not generate Skipped ### frames

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

一些用户有 1000 项要显示。

我还允许我的用户search/filter 保存在 recyclerView 中的项目。

列表初始显示正常

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

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

我尝试在我的 activity 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);

            }
        });

我的 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?

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

尝试以下操作:

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计算。

我还会检查您是否无意中 运行 陷入线程问题,例如 this blog

中描述的情况

编辑:

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

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