首页 > 解决方案 > android.view.ViewRootImpl$CalledFromWrongThreadException:只有创建视图层次结构的原始线程才能接触其视图。(RxJava)

问题描述

我发现很多关于我遇到的错误的文章,我知道我们只能从主线程更新 UI。让我告诉你我得到的整个错误:

E/RxEroor: The exception could not be delivered to the consumer because it has already cancelled/disposed of the flow or the exception has nowhere to go, to begin with. Further reading: https://github.com/ReactiveX/RxJava/wiki/What's-different-in-2.0#error-handling | android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

我通过使用这个得到错误:

  RxJavaPlugins.setErrorHandler(throwable -> {
        Log.e("RxEroor",throwable.getLocalizedMessage());
    });

我正在使用 rxjava 从改造网络调用中观察事物。这是我从片段调用 ViewModel 以获取数据。

compositeDisposable.add(songsOfCategoryViewModel.getAllSongs(1)
            .subscribeOn(AndroidSchedulers.mainThread())
            .subscribeWith(new DisposableSingleObserver<ServerResponse<JsonObject>>() {
                @Override
                public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull ServerResponse<JsonObject> jsonObjectServerResponse) {

                    if (jsonObjectServerResponse.isStatus()){
                        Log.i("Songs Of Category",jsonObjectServerResponse.getData().toString());
                        List<SongModel> serverSongList = new Gson()
                                .fromJson(jsonObjectServerResponse.getData().get("songs")
                                        .getAsJsonArray(),new TypeToken<List<SongModel>>(){}.getType());

                        localSongList.addAll(serverSongList);
                        songAdapter.notifyDataSetChanged();
                      /*  Observable
                                .fromIterable(serverSongList)
                                .observeOn(Schedulers.io())
                                .subscribeOn(AndroidSchedulers.mainThread())
                                .subscribe(new DisposableObserver<SongModel>() {
                                    @Override
                                    public void onNext(@io.reactivex.rxjava3.annotations.NonNull SongModel songModel) {
                                        Log.i("Song",songModel.getTitle());
                                        localSongList.add(songModel);
                                        songAdapter.notifyDataSetChanged();

                                    }

                                    @Override
                                    public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {

                                    }

                                    @Override
                                    public void onComplete() {
                                        Log.i("onComplete","Called");

                                    }
                                });
                        */

                    }else {
                        Log.e("Error",jsonObjectServerResponse.getMessage());
                    }
                }

                @Override
                public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
                    Log.e("Error",e.getMessage());

                }
            }));

如您所见,我提供了 AndroidSchedulers.mainThread() 来订阅。我正在获取 onSucces 方法的数据,但 recyclerview 适配器没有在 UI 上更新它。

让我告诉你最棘手的部分:如果我通过锁定屏幕或按下主页按钮将应用程序切换到前台并返回应用程序,我的 UI 会使用我收到的数据进行更新。

标签: androidrx-javarx-android

解决方案


你应该使用observeOn(AndroidSchedulers.mainThread())not subscribeOn(AndroidSchedulers.mainThread())。用于

.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())

subscribeOn用于指定 Observable 将在其上运行的调度程序。在您的情况下,它将是一个 IO 调度程序。

ObserveOn用于指定观察者将在其上观察此 Observable 的调度程序,即在这种情况下完成将是主线程


推荐阅读