Observable.range(11,10).subscribeOn(Schedulers.io())
.observeOn(Schedulers.io())
.subscribe(new Observer<Integer>() {
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull Integer integer) {
textView.setText(String.valueOf(integer));
Log.d(TAG, "onNext: "+Thread.currentThread().getName());
}
@Override
public void onError(@NonNull Throwable e) {
}
@Override
public void onComplete() {
}
});
onNext() supposed to run on separate thread, but how is it updating textview, which is on main thread?
It seems that at the very beginning of the lifetime of a view, there is a very short timespan where you are able to change the view off the main thread.
As you started a thread off the main thread, directly in onCreate()
, and this thread almost instantly returns a result (as there is no real work to do) you will not get a CalledFromWrongThreadException
when you adjust the view.
If you put a short delay (maybe it is different on your machine) - for me, 50ms
was enough - before the work in the thread / Observable starts, you will see the expected CalledFromWrongThreadException
.
Observable.just("first")
.subscribeOn(Schedulers.newThread())
.delay(50, TimeUnit.MILLISECONDS)
.observeOn(Schedulers.newThread())
.subscribe(item -> {
textView.setText(item); // after the delay you will get a CalledFromWrongThreadException
});
And this is not related to RxJava. Creating a Thread which updates the view immediately shows the same behavior:
new Thread(new Runnable() {
@Override
public void run() {
textView.setText("foo"); // no CalledFromWrongThreadException
}
}).start();
Looks like this issue goes back to ViewRootImpl checkThread()
which did not get called in this case. For further understanding follow the links below.
Despite, any change to a view should happen from the main thread. The scenario you have shown seems like a "lucky" side-effect.
Documentation