Preparing to cook the solution

The solution will be introduced in small steps -in the form of a cooking recipe- explaining the reasons to add each ingredient and what problem each one tries to solve.

TL;DR if you just want the solution scroll directly to the end to see the sequence of operators

Warming up the oven

The first RxJava ingredient that covers most of the needs of our goal is a BehaviorRelay from RxRelay (a.k.a. safe BehaviorSubject). This will provide subscription/unsubscription events, multicasting to multiple observers like a hot observable and finally a replay of the last emitted value to new observers.

The steps to prepare this ingredient are:

In doOnSubscribe() register the listener, event bus (cough!) or any other producer of events

In doOnUnsubscribe() un-register the listener, event bus or any other producer of events

When a new event is received from the producer, then call the relay to emit the event to all observers

A Relay is basically a Subject except without the ability to call onComplete or onError

Image copyright reactivex.io

This works fine, except for the fact that every new subscription to the observable causes an extra registration to the listener and every unsubscription from the observable causes an extra un-registration from the listener, even if there are more observers still subscribed to the observable.

This recipe can not be used with multiple concurrent observers.

The code above produces this output:

BehaviorRelayProblem -> observer-1 subscribes

BehaviorRelayProblem -> doOnSubscribe

BehaviorRelayProblem -> observer-1 -> onNext with 1

BehaviorRelayProblem -> observer-2 subscribes

BehaviorRelayProblem -> doOnSubscribe <= PROBLEM: unwanted call

BehaviorRelayProblem -> observer-2 -> onNext with 1

BehaviorRelayProblem -> observer-1 -> onNext with 2

BehaviorRelayProblem -> observer-2 -> onNext with 2

BehaviorRelayProblem -> observer-1 unsubscribes

BehaviorRelayProblem -> doOnUnsubscribe <= PROBLEM: unwanted call

BehaviorRelayProblem -> observer-2 unsubscribes

BehaviorRelayProblem -> doOnUnsubscribe