Как использовать android.support.v7.util.DiffUtil с RxJava, LiveData и не генерировать пропущенные ### кадры

Мое текущее приложение для Android использует LiveData для заполнения моего recyclerView.

У некоторых пользователей есть тысячи элементов для отображения.

Я также разрешаю своим пользователям искать / фильтровать элементы, хранящиеся в recyclerView.

Первоначальное отображение списка в порядке.

Однако, когда пользователь начинает искать / фильтровать список от 1000 до 1 или 2 элементов, пользовательский интерфейс действительно становится очень плохим, пользовательский интерфейс перестает отвечать на запросы в течение 10 секунд.

Мой адаптер RecyclerView использует android.support.v7.util.DiffUtil для управления изменениями элементов списка.

Я попытался использовать RxJava в методе onChange моей активности для выполнения различий в фоновом потоке.

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);

            }
        });

Мой адаптер 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.

Какую ошибку я сделал, чтобы по-прежнему видеть пропущенные кадры?

Можно ли различать большие изменения списка и при этом иметь отзывчивый пользовательский интерфейс?

используйте библиотеку поддержки Google пейджинг

pskink 01.11.2018 15:07

@pskink обрабатывает ли библиотека разбиения на страницы различение отображаемых элементов? особенно, когда количество отображаемых элементов резко меняется, например. от 0 до 5000 в миллисекундах?

Hector 01.11.2018 22:30

количество загружаемых элементов примерно 10-30, не больше, для этого и нужна подкачка

pskink 01.11.2018 23:00
0
3
275
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Опубликованный код теоретически не должен выполнять 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. Кроме того, если вы действительно хотите, чтобы это действие вступило в силу, вы должны переместить его как можно ниже, иначе позиция в исходном вопросе не повлияет на вычисление diff под ним.

Я бы также проверил, не возникли ли у вас непреднамеренно проблемы с потоками, такие как случаи, описанные в этот блог.

Редактировать:

Если вы меняете источник, вы можете использовать switchMap, но также можете использовать fromCallable:

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

@akamokd Я думал, что мне понадобится switchMap, поскольку каждый раз, когда пользователь меняет текст поиска, мне нужно заменить текущий поиск следующим введенным поисковым термином, иначе я получаю разногласия по списку элементов моего адаптера

Hector 04.11.2018 16:03

Ладно, на самом деле у вас есть что-то другое, кроме just. В этом случае да, вам нужен switchMap, но вам также нужно убедиться, что вы не блокируете сам switchMap с вычислением diff. Поместите разницу в fromCallable.

akarnokd 04.11.2018 16:08

Другие вопросы по теме