java.lang.IllegalStateException: 预期在主线程上被调用但是是 RxCachedThreadScheduler-1

java.lang.IllegalStateException: Expected to be called on the main thread but was RxCachedThreadScheduler-1

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

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有这个方法:

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
  }
}

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

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

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线程上执行,在主线程上查看订阅。