Rxjava: Confusing semantics between cache(int) and replay(int)

Created on 10 Jun 2015  路  4Comments  路  Source: ReactiveX/RxJava

It seems misleading that replay(1).refCount() != cache(1), especially when replay().refCount() == cache().

It's especially odd because each one cannot mimic the behavior of the other - cache() has no variant that limits the number of items to replay, whereas replay() has no variant that allows you to hint how large the ReplaySubject should be.

I see that this has been covered before (#1591, #2913), but I still feel like something could be done to clear up the matter. Not exactly sure what - maybe all it'd take is not having the javadoc for cache() reference replay().

Documentation Question

Most helpful comment

I agree that caching a limited number of elements using cache() would be handy sometimes, but it is important to note that replay().refCount() does not behave equal to cache() in all situations.

For example:

int i = 0; // actually a field or static
Observable<Integer> cached = Observable
            .defer(() -> Observable.just(i++, i++))
            .cache();
cached.subscribe(i -> System.out.println("sub 1: " + i));
cached.subscribe(i -> System.out.println("sub 2: " + i));

prints

sub 1: 0
sub 1: 1
sub 2: 0
sub 2: 1

compared to

int i = 0; // actually a field or static
Observable<Integer> replayed = Observable
            .defer(() -> Observable.just(i++, i++))
            .replay().refCount();
replayed.subscribe(i -> System.out.println("sub 1: " + i));
replayed.subscribe(i -> System.out.println("sub 2: " + i));

which results in

sub 1: 0
sub 1: 1
sub 2: 2
sub 2: 3

All 4 comments

I agree that caching a limited number of elements using cache() would be handy sometimes, but it is important to note that replay().refCount() does not behave equal to cache() in all situations.

For example:

int i = 0; // actually a field or static
Observable<Integer> cached = Observable
            .defer(() -> Observable.just(i++, i++))
            .cache();
cached.subscribe(i -> System.out.println("sub 1: " + i));
cached.subscribe(i -> System.out.println("sub 2: " + i));

prints

sub 1: 0
sub 1: 1
sub 2: 0
sub 2: 1

compared to

int i = 0; // actually a field or static
Observable<Integer> replayed = Observable
            .defer(() -> Observable.just(i++, i++))
            .replay().refCount();
replayed.subscribe(i -> System.out.println("sub 1: " + i));
replayed.subscribe(i -> System.out.println("sub 2: " + i));

which results in

sub 1: 0
sub 1: 1
sub 2: 2
sub 2: 3

That's interesting; I didn't know that refCount actively unsubscribes from the base subscription, though I guess it wouldn't really work otherwise.

If the upstream terminates, all subscribers go away and refCount starts from zero again.

I'm proposing the autoConnect() operator in #3023 so you can use replay(10).autoConnect() for now instead of a bounded cache().

I hope this problem has been clarified via the javadoc and the new autoConnect operator in release 1.0.14.

Was this page helpful?
0 / 5 - 0 ratings