serge.s
serge.s

Reputation: 21

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

I'm new here. I'm trying to use RxJava library for Android but getting error. The logic is to handle click events on button, then map it to get value from EditText, and then flatmap it to Single<String> which resolves value via network. I'm trying to run flatmap on IO thread using Schedulers.io(), but getting error:

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)

The code:

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 has this method:

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

Can someone help me to solve this issue? I need to run network calls on background thread, but receive the result on main thread.

Upvotes: 1

Views: 1182

Answers (1)

Kirill
Kirill

Reputation: 8311

You're using .subscribeOn(Schedulers.io()) for RxView.clicks(this.btnNext) event source. It means that RxView will subscribe on IO thread but it's not allowed. You should configure scheduler for your Single<String> source by flatMapSingle(key -> new Api(key).id().subscribeOn(Schedulers.io())). So the full code should be:

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

Now network operation will be performed on IO thread, view subscription on main thread.

Upvotes: 2

Related Questions