I\'m playing around with rxJava/rxAndroid and there\'s something very basic that doesn\'t behave as I\'d expect. I have this one observable and two subscribers:
This is because in fact those are two separate observables. They are "spawned" when you invoke subscribe()
. Therefore the steps you have provided are incorrect in sense that step 3 & 4 are just 1 & 2 but on a different observable.
But you see them as 1 1 1 2 2 2 because of thread on which the logging happens. If you were to remove the observeOn()
part then you would see emissions in a interwoven manner. To see this run code below:
@Test
public void test() throws InterruptedException {
final Scheduler single = Schedulers.single();
final long l = System.nanoTime();
Observable dataStream =
Observable.just(1, 2, 3)
.map(i -> System.nanoTime())
.subscribeOn(Schedulers.computation());
//.observeOn(single);
dataStream.subscribe(i -> System.out.println("1 " + Thread.currentThread().getName() + " " + (i - l)));
dataStream.subscribe(i -> System.out.println("2 " + Thread.currentThread().getName() + " " + (i - l)));
Thread.sleep(1000);
}
Output, at least in my run was(notice thread names):
1 RxComputationThreadPool-1 135376988
2 RxComputationThreadPool-2 135376988
1 RxComputationThreadPool-1 135486815
2 RxComputationThreadPool-2 135537383
1 RxComputationThreadPool-1 135560691
2 RxComputationThreadPool-2 135617580
and if you apply the observeOn()
it becomes:
1 RxSingleScheduler-1 186656395
1 RxSingleScheduler-1 187919407
1 RxSingleScheduler-1 187923753
2 RxSingleScheduler-1 186656790
2 RxSingleScheduler-1 187860148
2 RxSingleScheduler-1 187864889
As you have correctly pointed out, to get what you want you need the publish().refcount()
or simply share()
(it is an alias) operator.
This is because the publish()
creates a ConnectableObservable
which does not start emitting items until told to do so via the connect()
method. in which case if you do this:
@Test
public void test() throws InterruptedException {
final Scheduler single = Schedulers.single();
final long l = System.nanoTime();
ConnectableObservable dataStream =
Observable.just(1, 2, 3)
.map(i -> System.nanoTime())
.subscribeOn(Schedulers.computation())
.observeOn(single)
.publish();
dataStream.subscribe(i -> System.out.println("1 " + (i - l)));
dataStream.subscribe(i -> System.out.println("2 " + (i - l)));
Thread.sleep(1000);
dataStream.connect();
Thread.sleep(1000);
}
You will notice that for the first second(the first Thread.sleep()
invocation) nothing happens and just after the dataStream.connect()
is called the emissions happen.
refCount()
takes in a ConnectableObservable and hides from subscribers the need to call connect()
by counting how many subscribers are currently subscribed. What it does is upon first subscription it calls connect()
and after last unsubscription is unsubscribes from the original observable.
As to the mutual cancellation of the publish().autoConnect()
, afterwards you do get an observable but it has one special property, say that the original observable does an API call over the Internet(lasting 10 second), when you use it without share()
you will end up with as many parallel queries to the server as there were subscriptions over those 10 seconds. On the other hand with share()
you will have only one call.
You will not see any upside of it, if an observable that is shared completes its work very fast (like just(1,2,3)
).
autoConnect()
/refCount()
gives you an intermediate observable to which you subscribe to instead of the original observable.
If you are interested dive into this book: Reactive Programming with RxJava