How RXJava Scheduler/Threading works for different operator? - android

Can anyone please help me to explain which scheduler are running below code?
Completable.complete()
.subscribeOn(http://Schedulers.io ())
.observeOn(AndroidSchedulers.mainThread())
.delay(5000, TimeUnit.MILLISECONDS)
.doOnComplete(() -> liveDataState.postValue(""))
.subscribe()
My question is which schedulers are delay(), doOnComplete() and subscribe() are using io or mainThread?

After digging into RxJava threading last two days found the rule of thumbs for handling RxJava Threading/Scheduling:
observeOn works only downstream operator
subscribeOn works for both downstream and upstream operator
Consecutive/Multiple subscribeOn do not change the thread
Consequent observeOn do change the thread for downstream oerator
Unlike with subscribeOn(), we can use observeOn() multiple times for
seamless thread switching
Operator like delay(), interval() have default scheduler and can change the downstream scheduler as well
So, for my case:
Completable.complete() // IO scheduler based on subscribeOn scheduler
.subscribeOn(http://Schedulers.io ())
.observeOn(AndroidSchedulers.mainThread())
.delay(5000, TimeUnit.MILLISECONDS) // Default Computation scheduler
.doOnComplete(() -> liveDataState.postValue("")) // Computation scheduler by delay scheduler
.subscribe() // Computation scheduler by delay as well
Also, you can look into the marble diagram for more understanding:

Related

Why does Observable.interval() operator uses the computation as default scheduler?

In my Android app I'm using the interval() operator to schedule multiple periodic jobs (which may run simultaneously):
public class Job {
...
public void start(Runnable runnable, Scheduler scheduler) {
Observable
.interval(this.initialDelay, this.interval, this.timeUnit)
.observeOn(scheduler)
.subscribe(t -> runnable.run());
}
...
}
My questions is:
Why does it use the computation() as default scheduler for the interval() operator?
obviously I can use the overloaded method and send different scheduler but I'm not sure how it may affect the performances or anything else by changing the scheduler.

Confusion in Rx Java Android

Im new to rx and have some lines of code that confuse me:
Observable.just(1,2,3,4,5,6)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value ->
Log.i("TEST", "$value")
}
.dispose()
it will not log the result but when i comment out subscribeOn () and observeOn() or dispose() then it works perfectly, like this:
Observable.just(1,2,3,4,5,6)
.subscribe { value ->
Log.i("TEST", "$value")
}
.dispose()
or
Observable.just(1,2,3,4,5,6)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe { value ->
Log.i("TEST", "$value")
}
Can someone explain what happen inside this chain
When you write .subscribeOn(Schedulers.io()) this essentially means that Observable will operate on io thread, which will require a thread switch causing some delay.
by the time it happens you have already called the dispose() method which disposes the Observable hence you don't receive any output.
On the other hand if you remove
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
This means Observable will operate on the calling thread so no thread switch is required, hence you receive complete output before dispose() method call can be executed.
If you only remove dispose() then nothing is stopping the Observable from emitting its contents even though its executing on io
Observable.just(1,2,3,4,5,6) -> The Just operator converts an items into an Observable that emits these items.
subscribeOn() -> operator tells the source Observable which thread to emit and push items on all the way down to Observer
observeOn() -> it will switch and pass emissions using that Scheduler for the remaining (downstream) operations
subscribe() -> operator returns Disposable object. You should assign this object to variable or to CompositeDisposable object. All disposables should be dispose (using dispose() method) while your Activity or Fragment ends life to avoid memory leak.
More you can find here:
https://proandroiddev.com/understanding-rxjava-subscribeon-and-observeon-744b0c6a41ea
http://reactivex.io/documentation/operators.html#creating
You can also check Kotlin Coroutines as an alternative to RxJava

RxJava2 with Room error handling - Database main thread exception

I'm trying to retrieve items from a remote source, if this won't work (no internet) i'd like to retrieve cached items from a room database.
I have created a new single for when the error happens and I've specified on what thread it should subscribe and observe on. I still this exception though:
java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
This is the method for retrieving the items:
public LiveData<List<Article>> getNewsArticles() {
return LiveDataReactiveStreams.fromPublisher(
newsService.getNewsArticles()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.onErrorResumeNext(throwable ->
Single.just(newsDao.findAllForNumber(AMOUNT_OF_ARTICLES_PER_PAGE))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread()))
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSuccess(newsArticles -> Completable.fromAction(() ->
newsDao.insertAll(newsArticles))
.subscribeOn(Schedulers.io()))
.toFlowable());
}
LiveDataReactiveStreams converts it into a livedata object and handles the subscribtion, so my view only knows about livedata.
I just can't seem to make the onErrorResumeNext call work on a background thread.
Any help would be greatly appreciated!
ANSWER
I ended up solving tthe problem with the following code:
public LiveData<List<Article>> getNewsArticles() {
return LiveDataReactiveStreams.fromPublisher(
newsService.getNewsArticles()
.observeOn(Schedulers.io())
.doOnSuccess(newsArticles -> newsDao.insertAll(newsArticles))
.onErrorResumeNext(throwable -> Single.fromCallable(() -> newsDao.findAllForNumber(AMOUNT_OF_ARTICLES_PER_PAGE)))
.toFlowable());
}
In RxJava method subscribeOn specify the Scheduler on which an Observable will operate. But method observeOn specify the Scheduler on which an observer will observe this Observable.
For simple:
Single
.zip(observable1.getList(), observable2.getAnotherList()) // Simple zip for example
.observeOn(AndroidSchedulers.mainThread()) // switch to main thread
.map(mapper.map(list1, list2)) // this command will execute on main thread
.observeOn(Schedulers.io()) // switch to io thread
.map(anotherMapper.map(complexList)) // this command will execute on io thread
.observeOn(AndroidSchedulers.mainThread()) // switch to main thread
.subscribeOn(Schedulers.io()) // specify thread for zip command
ObserveOn works only downstream. All the methods following the observeOn have been moved to the IO thread. While the methods prior to the observeOn are still in the main thread.
In your example you somewhere try to call room dao command on main thread, and system does not allow to execute on main thread. You can set breakpoint on each command then in IDE look exactly thread name where command will be execute.
For more complex examples see this article.

How to call a method after a delay in android using rxjava?

I'm trying to replace my Handler method with RxJava.
My requirement:
I want to call the method getTransactionDetails() only after 5
seconds.
This my working code using Handler:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getTransactionDetails();
}
}, 5000);
Rx java code - it's not working:
Observable.empty().delay(5000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnNext(o -> getTransactionDetails())
.subscribe();
This is how I would do it:
Completable.timer(5, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.subscribe(this::getTransactionDetails);
A Completable represents a deferred computation with no value but an indication for completion or exception. The static method call timer() returns a Completable that signals completion after the specified time period has elapsed, and the subscribe() call will mean that the method getTransactionDetails() will be called on the current object when the timer fires. By supplying a Scheduler as the last argument to Completable.timer() you control which thread is used to execute getTransactionDetails().
doOnNext() is for side effects. It could be use for example for logging purpose, because logging doesn't alter the flow of data. But you want to pass down the result of getTransactionDetails(), so you should use map instead.
Second, Observable.empty() create an Observable that just propagate the finish/dispose message, it trigger neither doOnNext() neither map(). You could fix this using Observable.just() instead but a more idiomatic way would be to use Observable.timer():
Observable.timer(5000, TimeUnit.MILLISECONDS)
.map(o -> getTransactionDetails())
.observeOn(AndroidSchedulers.mainThread())
.subscribe( ... );
A final note on Schedulers. Observable.timer() and delay() are executed on the computation scheduler by default so you don't need to call .subscribeOn(Schedulers.io()) to execute getTransactionDetails() outside of main thread. Observable.timer() and delay() could take a Scheduler as a parameter if you want to control this. So you need to call .observeOn(AndroidSchedulers.mainThread()) if you want to use getTransactionDetails() result on UI thread. Every operator after observeOn() is executed on the defined Scheduler, so you have to put observeOn() after computation.
Edit: This is of course if you care about the result of getTransactionDetails(). If not, see Clyde answer.
Observable
.timer( 5000, TimeUnit.MILLISECONDS )
.subscribeOn(Schedulers.io())
.map(o -> getTransactionDetails() )
.subscribe();
you dont need observeOn because subscribe empty.
use timer it will be more correct way
It's not working, because delay() needs something to be emitted, but empty() actually emits nothing.
Instead, you should use Observable.timer().
Delay subscription already defined. Your example can be implemented in this way:
getTransactionDetails().delaySubscription(5000, TimeUnit.MILLISECONDS)
Try this
Observable.just(true).delay(5000, TimeUnit.MILLISECONDS)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(o -> getTransactionDetails())
.subscribe();
If you want a disposable that can be used with the view then use a Completable
Completable returns an Object which terminates as soon as one of the source Completables terminates (normally or with an error) and cancels all other Completables.
Eg :
Completable.timer(5, TimeUnit.SECONDS, AndroidSchedulers.mainThread())
.subscribe(() -> {
// code after delay here
});
If you want for a service to get complete i would recommend a Subscription
Eg :
observable.timer(5000, TimeUnit.MILLISECONDS)
.map(o -> {
// your code after delay here
})
.observeOn(AndroidSchedulers.mainThread())
.subscribe( ()-<{
// enter the service here
} );

RxJava subscribeOn and observeOn not override the original Scheduler set before?

I used RxJava in android with Retrofit 2 and I have invoked subscribeOn(Schedulers.io()) android observeOn(AndroidSchedulers.mainThread()) global before subscribe().
However, sometime I would like to call subscribeOn(Schedulers.immediate()) android observeOn(Schedulers.immediate()) to override the Schedulers set before to get synchronized process. But I found it doesn't work, android works would be still processed on io() thread, android result processed by mainThread().
Why?
That's just the way RxJava works.
Take a look at this video tutorial, starting at the 12:50 mark. So given the example in the video:
Observable.just(1, 2, 3)
.subscribeOn(Schedulers.newThread())
.subscribeOn(Schedulers.io())
.subscribe(System.out::println);
What happens is that subscribeOn() nests all calls. In this case subscribeOn(Schedulers.io()) is spawned first and subscribes everything above it on the io thread. But then subscribeOn(Schedulers.newThread()) is spawned next and it takes priority (since it was called last) to subscribe everything on it instead. There is no building a chain of threads. In this example, you are essentially spawning the io thread for no good reason.
To better handle the subscribeOn() and observeOn() methods, I suggest you take a look at this post from the same author of the video. What he is proposing is to use a Transformer to wrap the call to these methods:
Transformer is actually just Func1<Observable<T>, Observable<R>>. In
other words: feed it an Observable of one type and it'll return an
Observable of another. That's exactly the same as calling a series of
operators inline.
This way, you can have a method like so:
<T> Transformer<T, T> applySchedulers() {
return observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
}
Or, if you want to reuse your transformers, you can have the following setup:
final Transformer schedulersTransformer =
observable -> observable.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread());
#SuppressWarnings("unchecked")
<T> Transformer<T, T> applySchedulers() {
return (Transformer<T, T>) schedulersTransformer;
}
Then the above example would look like:
Observable.just(1, 2, 3)
.compose(applySchedulers())
.subscribe(System.out::println);
Hope that helps.

Categories

Resources