Диспетчеризация DiffResult приводит к «Обнаружено несоответствие. Иногда возникает ошибка неправильного адаптера держателя вида positionViewHolder

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

Код диспетчеризации в адаптере:

 public void dispatchStreams(List<StreamV3> streams, @Nullable DiffUtil.DiffResult diffResult) {

    if (streams == null) return;

    streamsList.clear();
    streamsList.addAll(streams);

    if (diffResult != null) {
        diffResult.dispatchUpdatesTo(this);
    }
}

У меня "Обнаружено несоответствие. Недопустимая ошибка адаптера держателя представления positionViewHolder на некоторых устройствах. И я не могу понять, что не так с моим кодом. Минимальный SDK 21, целевой SDK 26, версия RecyclerView — 26.0.0. Я знаю об обходном пути с расширением LinearLayoutManager и молчаливым обнаружением этой ошибки, но это плохое решение, и я считаю, что здесь должно быть лучше.

Может ли кто-нибудь оказать любую помощь, пожалуйста?


person Olexii Muraviov    schedule 04.10.2017    source источник
comment
@Черный пояс, да   -  person Olexii Muraviov    schedule 04.10.2017
comment
Я могу рассказать вам, как мы это исправим, но мы точно не знаем, почему. Было много проб и ошибок   -  person Blackbelt    schedule 04.10.2017
comment
@Blackbelt хорошо, я был бы рад услышать твое решение   -  person Olexii Muraviov    schedule 04.10.2017


Ответы (2)


Я нашел решение этой проблемы в этом ответе.

Похоже, проблема вызвана свойством supportsPredictiveItemAnimations в менеджерах компоновки. Когда я устанавливаю для него значение false, сбоев больше не происходит.

public class LinearLayoutManagerWrapper extends LinearLayoutManager {

 public LinearLayoutManagerWrapper(Context context) {
   super(context);
 } 

 public LinearLayoutManagerWrapper(Context context, int orientation, boolean reverseLayout) {
   super(context, orientation, reverseLayout);
 }

 public LinearLayoutManagerWrapper(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
   super(context, attrs, defStyleAttr, defStyleRes);
 }

 @Override
 public boolean supportsPredictiveItemAnimations() {
   return false;
 }
}
person Olexii Muraviov    schedule 05.10.2017
comment
Включите фрагмент кода вместе со ссылкой на случай, если исходный вопрос или ответ будут удалены. - person Debanjan; 27.03.2018
comment
@Debanjan конечно :) - person Olexii Muraviov; 28.03.2018
comment
Что делать, если вам нужно прогностическоеItemAnimation? В противном случае вы вообще не сможете использовать эту функцию! - person Code Wiget; 13.04.2020

Столкнулся с этой проблемой при написании Rx RV Diff для запуска в фоновом потоке. Установка для supportsPredictiveItemAnimations значения false — это обходной путь, который предотвращает сбой, но на самом деле не решает проблему.

Причиной этого исключения в моем случае была мутация набора данных в фоновом потоке.

// Diff and update the RV asynchronously
fun update(list: List<D>) {
    Observable
        .create<Pair<List<D>, DiffUtil.DiffResult>> {
            // runs it asynchronous
            val result = DiffUtil.calculateDiff(
                diffCallback.apply {
                    newList = list
                }
            )

            it.onNext(Pair(diffCallback.newList, result))
            it.onComplete()
        }
        .takeUntil(destroyObservable) // observe the Lifecycle of the Frag
        .subscribeOn(Schedulers.computation()) // run it async
        .observeOn(AndroidSchedulers.mainThread()) // jump to the main thread
        .subscribe {
            // Set the new list
            dataSet = it.first.map { it }
            it.second.dispatchUpdatesTo(this@ListComponentAdapter)
        }
}
person Juliano Moraes    schedule 27.02.2019
comment
У меня такая же проблема. Мне нравится ваше решение, но можете ли вы объяснить, как вы используете destroyObservable? Возможно, обновление может быть методом адаптера и вернуть наблюдаемое, чтобы представление могло управлять его удалением. - person GuilhE; 07.09.2019