0

I am new into RxJava and I was under the impression that for each event each subscriber is being notified. So if we have N subscribers and a stream of X events the onNext for each of the N subscribers would be called. But when I run the following code:

public static void main(String[] args) {
        Observable<String> source = Observable.create(emitter -> {
            emitter.onNext("Hello");
            emitter.onNext("Foo");
            emitter.onNext("Bar");
            emitter.onNext("RxJava");
        });

        source.subscribe(e -> System.out.println("Observer 1: " + e));
        source.subscribe(e -> System.out.println("Observer 2: " + e));
    } 

I see:

Observer 1: Hello
Observer 1: Foo
Observer 1: Bar
Observer 1: RxJava
Observer 2: Hello
Observer 2: Foo
Observer 2: Bar
Observer 2: RxJava  

So basically after all the onNext are done only then the next observer is being triggered.

I was expecting to see:

Observer 1: Hello 
Observer 2: Hello
Observer 1: Foo
Observer 2: Foo
Observer 1: Bar
Observer 2: Bar
Observer 1: RxJava
Observer 2: RxJava 

That seems to me inefficient for very long streams, am I doing something wrong?

Jim
  • 3,845
  • 3
  • 22
  • 47

1 Answers1

2

RxJava sequences are synchronous by default thus the subscribe call above will run your emission code right there. To achieve the interleaving, you need a way to tell the source when both consumers are ready to receive. This can be done several ways:

ConnectableObservable<String> source = Observable.<String>create(emitter -> {
            emitter.onNext("Hello");
            emitter.onNext("Foo");
            emitter.onNext("Bar");
            emitter.onNext("RxJava");
        }).publish();

        source.subscribe(e -> System.out.println("Observer 1: " + e));
        source.subscribe(e -> System.out.println("Observer 2: " + e));

        source.connect();

or

ConnectableObservable<String> source = Observable.<String>create(emitter -> {
            emitter.onNext("Hello");
            emitter.onNext("Foo");
            emitter.onNext("Bar");
            emitter.onNext("RxJava");
        }).publish().refCount(2);

        source.subscribe(e -> System.out.println("Observer 1: " + e));
        source.subscribe(e -> System.out.println("Observer 2: " + e));
akarnokd
  • 69,132
  • 14
  • 157
  • 192
  • `RxJava sequences are synchronous by default` yes but what I had in mind is a sequential loop over all observers for each string so no concurrency involved. – Jim Jun 11 '21 at 14:18
  • Could you elaborate what the 2 approaches do? I am completely new to RxJava – Jim Jun 11 '21 at 14:19
  • I thought it would be something like `for(subscriber: subsribers) subscribe.next(value);` called for each value – Jim Jun 12 '21 at 07:35
  • What does `connect` and `refcount` on `publish` do exactly? – Jim Jun 12 '21 at 07:36
  • `connect`: lets you line up observers before the observable is asked to emit. `refCount` establishes this connection when there are certain number of observers ready. `publish` does that `for each observer` without running the observable multiple times. – akarnokd Jun 12 '21 at 07:51
  • The code you shared does not compile for me without `io.reactivex.rxjava3.annotations.NonNull` why is that? I.e. `@NonNull ConnectableObservable source` – Jim Jun 12 '21 at 15:13
  • So if I understand correctly what is happening is the following: In my version of the code, the emitter starts sending the strings as soon as the first subscriber subscribes, and by the time the second subscriber subscribes, the first series of events/string have already been consumed by subscriber 1? Is my understanding correct? – Jim Jun 12 '21 at 17:00
  • When would I use `ConnectableObservable` and when `Observable` then? – Jim Jun 12 '21 at 17:00
  • 1) Right, they were missing ``. 2) Yes, that's correct. 3) When you need use multiple observers to start observing at once but not run the source multiple times. – akarnokd Jun 13 '21 at 08:07