I've seen patterns like this:
Observable<String> nameChanges = nameDataSource.changes().share();
// One subscriber
autoUnsubscribe(nameChanges.subscribe(() -> { ... }));
// Another subscriber
autoUnsubscribe(nameChanges.map(...).filter(...).subscribe(...));
// autoUnsubscribe is called when the UI is torn down
My question is:
Why is it necessary to call share()
whenever I want to listen to the Observable in multiple places?
Why is not share()
the default behavior for all observables?
It would be nice if the code above worked the same even without .share()
. I would not have to think about when I need to share an Observable, and when I don't.
Is it for performance reasons because having a single subscriber is a special case that can be handled more efficiently?
From the docs this is not clear to me:
share() returns a new ObservableSource that multicasts (shares) the original ObservableSource. As long there is at least one Observer this ObservableSource will be subscribed and emitting data.
There are two kinds of Observable
s: cold and hot. Cold Observable
s start producing items when there is an Observer
to them and they do it on an individual basis. Subscribing with multiple Observer
s will result in multiple runs of the same cold Observable
. An example of this is an Observable
that issues a network request.
In contrast, a hot Observable
can produce items with or without the presence of Observer
s. These Observable
s usually multicast the same items to all of their current Observer
s. An example of this is an Observable
of button clicks.
To turn a cold Observable
into a hot one, you can use publish()
which will make sure only a single subscription is established to the source Observable
no matter how many Observer
s there are. Thus, the chain will now act as a hot multicasting Observable
from the Observer
s' perspective.
However, often it is not economic to keep an originally cold Observable
running after all Observer
s of publish()
have gone away, therefore the refCount()
operator can be used to keep track of them and stop the source when there are no interesting parties left.
If your source is already hot, you don't need share()
.
Why is not share() the default behavior for all observables?
Actually, this property is one of the important contributions of the modern reactive programming paradigm: the distinction of the hot and cold Observable
s.
However, multicasting is expensive on itself because you have to keep track of the set of current Observer
s in order to notify them with new events, and this can lead to all sorts of logical race conditions to be defended against. A cold Observable
is known to talk only to a single Observer
so there is no need for the extra tracking overhead.