DiffResult调度导致“检测到不一致”。有时,视图持有者适配器positionViewHolder错误无效

问题描述 投票:4回答:2

我有一个RxJava2 Observable,它接受两个列表,为它们计算diff结果并将此数据发送到适配器。主线程上的适配器分派更新。

适配器中的调度代码:

 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错误无效。我无法弄清楚我的代码有什么问题。 Min SDK 21,Target SDK 26,RecyclerView版本为26.0.0。我知道扩展LinearLayoutManager并默默地捕获此错误的解决方法,但这是一个糟糕的解决方案,我相信这里应该更好。

有人可以提供任何帮助吗?

android android-recyclerview adapter android-viewholder
2个回答
9
投票

我在这个answer找到了解决这个问题的方法

似乎问题是由布局管理器上的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;
 }
}

1
投票

在编写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)
        }
}
© www.soinside.com 2019 - 2024. All rights reserved.