Search code examples
androidrx-javarx-android

When to use doOnTerminate vs doOnUnsubscribe?


I need to be notified when something subscribes to my observable. I also need to be notified that the observable has either errored or completed. So I thought I should use doOnSubscribe:

register an action to take when an observer subscribes to an Observable

and doOnTerminate:

register an action to take when an Observable completes, either successfully or with an error

Then I saw doOnUnsubscribe:

register an action to take when an observer unsubscribes from an Observable

and thought the symmetry of doOnSubscribe/doOnUnsubscribe would be better.

So, will doOnTerminate always be called before doOnUnsubscribe? If I just want to know that things are "done", does it really matter which I choose?


Solution

  • The way unsubscribe happens in your reactive flow will determine which one from doOnUnsubscribe or doOnTerminate you can use. The following can be the cases:

    Observable completion/error triggers unsubscribe
    In such a scenario both doOnTerminate and doOnUnsubscribe will be called with doOnTerminate being called first.

    The below example will print both terminated and unsubscribed.

    Subscription subscribe = Observable.empty() // source terminates immediately
        .subscribeOn(Schedulers.newThread()) 
        .doOnTerminate(() -> System.out.println("terminated"))
        .doOnUnsubscribe(() -> System.out.println("unsubscribed"))
        .subscribe();
    
    TimeUnit.SECONDS.sleep(1);
    subscribe.unsubscribe(); // by this time already unsubscribe would have happened
    

    Programatic call to unsubscribe before Observable completes
    In such a scenario only doOnUnsubscribe will be called. The chance of this happening is more prevalent when you have a source which runs infinitely or a source which is hot like an observable for user clicks.

    The below example will only print unsubscribed.

    Subscription subscribe = Observable.never() // source never terminates
        .subscribeOn(Schedulers.newThread())
        .doOnTerminate(() -> System.out.println("terminated"))
        .doOnUnsubscribe(() -> System.out.println("unsubscribed"))
        .subscribe();
    
    TimeUnit.SECONDS.sleep(1);
    subscribe.unsubscribe(); // this will trigger unsubscribe