首页 > 解决方案 > java.lang.IllegalStateException:应在主线程上调用,但为 RxCachedThreadScheduler-1

问题描述

我是新来的。我正在尝试将 RxJava 库用于 Android,但出现错误。逻辑是处理按钮上的点击事件,然后将其映射到从 中获取值EditText,然后通过网络flatmapSingle<String>其解析为值。我正在尝试flatmap使用 IO 线程运行Schedulers.io(),但出现错误:

E/MainActivity: Login error
    java.lang.IllegalStateException: Expected to be called on the main thread but was RxCachedThreadScheduler-1
        at com.jakewharton.rxbinding3.internal.Preconditions.checkMainThread(mainThread.kt:28)
        at com.jakewharton.rxbinding3.view.ViewClickObservable.subscribeActual(ViewClickObservable.kt:35)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:32)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableFilter.subscribeActual(ObservableFilter.java:30)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableDoOnEach.subscribeActual(ObservableDoOnEach.java:42)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableMap.subscribeActual(ObservableMap.java:32)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableFlatMapSingle.subscribeActual(ObservableFlatMapSingle.java:48)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableObserveOn.subscribeActual(ObservableObserveOn.java:45)
        at io.reactivex.Observable.subscribe(Observable.java:12267)
        at io.reactivex.internal.operators.observable.ObservableSubscribeOn$SubscribeTask.run(ObservableSubscribeOn.java:96)
        at io.reactivex.Scheduler$DisposeTask.run(Scheduler.java:578)
        at io.reactivex.internal.schedulers.ScheduledRunnable.run(ScheduledRunnable.java:66)
        at io.reactivex.internal.schedulers.ScheduledRunnable.call(ScheduledRunnable.java:57)
        at java.util.concurrent.FutureTask.run(FutureTask.java:266)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
        at java.lang.Thread.run(Thread.java:764)

编码:

RxView.clicks(this.btnNext)
  .map(none -> this.editTextKey.getText().toString())
  .filter(x -> !x.isEmpty())
  .flatMapSingle(key -> new Api(key).id())
  .observeOn(AndroidSchedulers.mainThread())
  .subscribeOn(Schedulers.io())
  .subscribe(this::showId, err -> {
    Log.e(this.getClass().getSimpleName(), "Login error", err);
  })

Api 类有这个方法:

class Api {

  private final String apiKey;

  public Api(final String apiKey) {
    this.apiKey = apiKey;
  }

  Single<String> id() {
    // some code to fetch user id by key from remote server
  }
}

有人可以帮我解决这个问题吗?我需要在后台线程上运行网络调用,但在主线程上接收结果。

标签: javaandroidrx-java

解决方案


您正在使用.subscribeOn(Schedulers.io())事件RxView.clicks(this.btnNext)源。这意味着RxView将订阅 IO 线程,但这是不允许的。您应该为您的Single<String>源配置调度程序flatMapSingle(key -> new Api(key).id().subscribeOn(Schedulers.io()))。所以完整的代码应该是:

RxView.clicks(this.btnNext)
  .map(none -> this.editTextKey.getText().toString())
  .filter(x -> !x.isEmpty())
  .flatMapSingle(key -> new Api(key).id().subscribeOn(Schedulers.io()))
  .observeOn(AndroidSchedulers.mainThread())
  .subscribe(this::showId, err -> {
    Log.e(this.getClass().getSimpleName(), "Login error", err);
  })

现在网络操作将在 IO 线程上执行,在主线程上查看订阅。


推荐阅读