RxJava。订阅开始时的初始onNext?

时间:2014-12-12 12:45:15

标签: java rx-java

我正在尝试使用Observable实现一个发出更改的类。 当对此observable进行订阅时,我想发送一个启动/初始化事件。然后我想发送通常的事件。

例如。假设我有两个不同的订户A和B.A和B在不同的时间开始订阅。如果MyClass.getChanges()发出事件号。 1,2,3,4和5。

如果A在事件1,2之间开始订阅,那么它应该收到以下事件: InitialEvent,2,3,4,5。

如果B在事件4和5之间开始订阅,那么B应该收到以下事件: InitialEvent,5。

如何使用RxJava执行此操作?

谢谢!

修改1

我想我需要解释一下每次发出时“InitialEvent”都不同。每次新订户开始从getChanged()订阅时,它都是由MyClass计算的。

我的场景是MyClass包含一个列表。 “initialEvent”包含订阅完成时的列表。然后,每个对此列表的更改都从getChanges()发出。

5 个答案:

答案 0 :(得分:0)

您正在寻找的是PublishSubject。主题热Observables,因为在开始发布项目之前,他们不会等待Observerssubscribe。以下是关于Subjects的一些信息。

以下是您的用例

的快速演示
    PublishSubject<String> subject = PublishSubject.create();
    Observable<String> InitEvent = Observable.just("init");
    Observable<String> A = subject.asObservable();
    Observable<String> B = subject.asObservable();

    subject.onNext("1");

    A.startWith(InitEvent)
            .subscribe(s -> System.out.println("A: " + s));

    subject.onNext("2");
    subject.onNext("3");
    subject.onNext("4");

    B.startWith(InitEvent)
            .subscribe(s -> System.out.println("B: " + s));

    subject.onNext("5");

答案 1 :(得分:0)

可能不是很优雅的方式如何使用旗帜?看起来你只想替换第一个发出的事件。

e.g。对于一个订阅,以下逻辑:

boolean firstTimeA = true;

myCustomObservable.subscribe(s -> {
   System.out.println(firstTimeA ? "initEvent" : s.toString());
   if(firstTimeA) firstTimeA = false;
});

由于您想要第二次订阅,只需创建一个firstTimeB并将其更新为您的B订阅。

答案 2 :(得分:0)

如果我理解你的问题,那么这样的事情对你有用

int last = 0;
Observable obs;
List<Integer> list = new ArrayList<>();

public SimpleListObservable() {
    obs = Observable.create(new Observable.OnSubscribe<Integer>() {
        @Override
        public void call(Subscriber<? super Integer> subscriber) {
            while(last < 30) {
                last++;
                list.add(last);
                subscriber.onNext(last);
            }
            subscriber.onCompleted();
        }
    });
}

public Observable<Integer> process() {
    return Observable.from(list).concatWith(obs);
}

当source observable收集值时,它们会被添加到List(您可以根据需要转换项目,过滤掉它们等),然后当ObserverB订阅时,它将获得重播在继续源可观察输出之前已经在List中收集的项目。

这个简单的测试应该证明结果

public void testSequenceNext() {
    final SimpleListObservable obs = new SimpleListObservable();

    final Observer<Integer> ob2 = Mockito.mock(Observer.class);

    obs.process().subscribe(new Observer<Integer>() {
        @Override
        public void onCompleted() {
            ob1Complete = true;
        }

        @Override
        public void onError(Throwable e) {
            e.printStackTrace();
        }

        @Override
        public void onNext(Integer integer) {
            System.out.println("ob1: " + integer);
            if (integer == 20) {
                obs.process().subscribe(ob2);
            }
        }
    });

    ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class);

    Mockito.verify(ob2, Mockito.times(30)).onNext(captor.capture());

    for (Integer value : captor.getAllValues()) {
        System.out.println(value);
    }

}

答案 3 :(得分:0)

您如何看待这一点,当然我正在打电话时,我已经成为我的API的一部分:

public class StreamOfSomething {
    new StreamOfSomething() {
        // source of events like
        events = Observable.range(0, 1_000_000_000)
                           .doOnNext(set::add) // some operation there
                           .map(Event::change)
                           .publish()
                           .refCount();
    }

    public Observable<Event> observeChanges() {
        return events.startWith(
                 Observable.just(Event.snapshot(set))); // start stream with generated event
    }
}

客户端可以执行以下操作:

Observable.timer(2, 4, TimeUnit.SECONDS)
          .limit(2)
          .flatMap(t -> theSourceToWatch.observeChanges().limit(10))
          .subscribe(System.out::println);

但是请注意,如果您处于多线程环境中,则在订阅阻止任何修改时可能需要进行同步,否则列表可能会在发出之前发生更改。或者完全围绕可观察者重写这个课程,但我还不知道如何实现这个目标。

答案 4 :(得分:0)

很抱歉在2年后发布,但我有同样的需求,发现这个问题没有答案。

我所做的是以下内容:

public Observable<Event> observe() {
    return Observable.defer(() -> 
        subject.startWith(createInitialEvent())
    );
}

这个想法如下:

  • defer()在观察者订阅方法observe()返回的Observable时执行传入的lambda表达式。基本上,它执行subject.startWith(...),它返回一个Observable,它是订阅者的实际事件源。
  • subject.startWith(...)发出一个初始事件(由startWith(...)指定),然后是主体发出的事件。

所以,如果我回到原帖: 如果观察者在事件1,2之间开始订阅,那么它应该收到以下事件:InitialEvent,2,3,4,5。