Reputation: 21
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
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