Investigating the flow of an Observable

The logging inside the steps of an Observable is a very powerful tool when one wants to understand how they work. If you are in doubt at any point as to what's happening, add logging and experiment. A few quick iterations with logs will definitely help you understand what's going on under the hood.

Let's use this technique to analyze a full flow of an Observable. We will start off with this script:

private void log(String stage, String item) {
Log.d("APP", stage + ":" + Thread.currentThread().getName() + ":" +
item);
}

private void log(String stage) {
Log.d("APP", stage + ":" + Thread.currentThread().getName());
}
Observable.just("One", "Two")
.subscribeOn(Schedulers.io())
.doOnDispose(() -> log("doOnDispose"))
.doOnComplete(() -> log("doOnComplete"))
.doOnNext(e -> log("doOnNext", e))
.doOnEach(e -> log("doOnEach"))
.doOnSubscribe((e) -> log("doOnSubscribe"))
.doOnTerminate(() -> log("doOnTerminate"))
.doFinally(() -> log("doFinally"))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(e -> log("subscribe", e));

It can be seen that it has lots of additional and unfamiliar steps (more about this later). They represent different stages during the processing of an Observable. So, what's the output of the preceding script?:

doOnSubscribe:main
doOnNext:RxCachedThreadScheduler-1:One
doOnEach:RxCachedThreadScheduler-1
doOnNext:RxCachedThreadScheduler-1:Two
doOnEach:RxCachedThreadScheduler-1
doOnComplete:RxCachedThreadScheduler-1
doOnEach:RxCachedThreadScheduler-1
doOnTerminate:RxCachedThreadScheduler-1
doFinally:RxCachedThreadScheduler-1
subscribe:main:One
subscribe:main:Two
doOnDispose:main

Let's go through some of the steps. First of all, by calling .subscribe() the doOnSubscribe block was executed. This started the emission of items from the Observable as we can see on the doOnNext and doOnEach lines. Finally, as the stream finished, termination life cycle was activated and methods doOnComplete, doOnTerminate and doOnFinally were called.

Also, the reader will note that the doOnDispose block was called on the main thread along with the subscribe block.

The flow will be a little different if .subscribeOn() and .observeOn() calls won't be there:

doOnSubscribe:main
doOnNext:main:One
doOnEach:main
subscribe:main:One
doOnNext:main:Two
doOnEach:main
subscribe:main:Two
doOnComplete:main
doOnEach:main
doOnTerminate:main
doOnDispose:main
doFinally:main

You will readily note that now, the doFinally block was executed after doOnDispose while in the former setup, doOnDispose was the last. This happens due to the way Android Looper Schedulers code blocks for execution and the fact that we used two different threads in the first case.

The takeaway here is that whenever you are unsure of what is going on, you can start logging actions (and the thread they are running on) to see what's actually happening.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.58.194