[英]RxJava. Initial onNext when subscription starts?
I'm trying to implement a class that emits changes using an Observable. 我正在尝试实现一个使用Observable发出更改的类。 When a subscription is done to this observable I want to send an starting/initialization event. 当订阅到此可观察对象时,我想发送一个启动/初始化事件。 Then I want to send the usual events. 然后,我想发送平常的事件。
For example. 例如。 Lets say I have two different subscribers A and B. A and B starts subscribing at different times. 可以说我有两个不同的订户A和B。A和B在不同的时间开始订阅。 If MyClass.getChanges() emits event no. 如果MyClass.getChanges()发出事件号。 1,2,3,4 and 5. 1,2,3,4和5
If A starts it subscription between event 1,2 then it should receive the following events: InitialEvent, 2, 3, 4, 5. 如果A在事件1,2之间开始订阅,则它应接收以下事件:InitialEvent,2、3、4、5。
If B starts it subscription between event 4 and 5, then B should receive the following events: InitialEvent, 5. 如果B在事件4和5之间开始订阅,那么B应该收到以下事件:InitialEvent,5。
How to do this using RxJava? 如何使用RxJava做到这一点?
Thanks! 谢谢!
Edit 1 编辑1
I think I need to explain that the "InitialEvent" is different each time it's emitted. 我想我需要解释一下,每次发出“ InitialEvent”都是不同的。 It's calculated by MyClass each time a new subscriber starts to subscribe from getChanged(). 每次新订阅者开始从getChanged()进行订阅时,它都是由MyClass计算的。
My scenario is that MyClass contains a list. 我的情况是MyClass包含一个列表。 The "initialEvent" contains the list at the moment when the subscription is done. 订阅完成后,“ initialEvent”将包含该列表。 Then each change to this list is emitted from getChanges(). 然后,从getChanges()发出对此列表的每次更改。
What you're looking for is PublishSubject
. 您正在寻找的是PublishSubject
。 Subjects are hot Observables
, in that they do not wait for Observers
to subscribe
to them before beginning to emit their items. 主题是热门的Observables
,因为它们在开始发出项目之前不等待Observers
进行subscribe
。 Here's a bit of info on Subjects . 以下是有关Subject的一些信息。
Here's a quick demo of your use-case 这是您的用例的快速演示
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");
Possibly not really elegant way how about just using a flag? 可能不是很优雅的方式,仅使用标志呢? It looks like you just want to replace the first emitted event. 看来您只想替换第一个发出的事件。
eg for one subscription the following logic: 例如,对于一个订阅,以下逻辑:
boolean firstTimeA = true;
myCustomObservable.subscribe(s -> {
System.out.println(firstTimeA ? "initEvent" : s.toString());
if(firstTimeA) firstTimeA = false;
});
And since you want to have a second subscription just create a firstTimeB
and update it your B subscription. 并且由于您想要第二个订阅,只需创建一个firstTimeB
并将其更新为您的B订阅即可。
If I understand what you are asking something like this should work for you 如果我了解您的要求,这样的事情应该对您有用
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);
}
As the source observable collects values they are added to the List
(you can transform the items as you see fit, filter them out, etc) and then when ObserverB
subscribes it will get a replay of the items already collected in the List
before continuing with the source observable output. 当源Observable收集值时,它们将被添加到List
(您可以按自己认为合适的方式变换项目,将其过滤掉等),然后当ObserverB
订阅时,它将重放List
已收集的项目,然后继续操作。源可观察的输出。
This simple test should demonstrate the outcome 这个简单的测试应该证明结果
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);
}
}
What do you think of this, I've made part of my API of course as I'm on a phone : 您对此有何看法,我在打电话时当然已经成为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
}
}
And the client can do something like : 客户可以执行以下操作:
Observable.timer(2, 4, TimeUnit.SECONDS)
.limit(2)
.flatMap(t -> theSourceToWatch.observeChanges().limit(10))
.subscribe(System.out::println);
Note however if you are in a multithreaded environment you may have to synchronize when you are subscribing to block any modification, otherwise the list may change before it get's emitted. 但是请注意,如果您在多线程环境中,则在订阅阻止任何修改时可能必须同步,否则列表可能会在发出之前更改。 Or rework this class completely around observables, I don't know yet how to achieve this though. 还是完全围绕可观察变量重做该类,尽管我还不知道该如何实现。
Sorry to post this 2 years later, but I had the same need and found this question unanswered. 很抱歉在两年后发布,但是我有同样的需求,发现这个问题没有答案。
What I did is the following: 我所做的是以下几点:
public Observable<Event> observe() {
return Observable.defer(() ->
subject.startWith(createInitialEvent())
);
}
The idea is the following: 这个想法如下:
So, if I come back to the original post: if an observer starts it subscription between event 1,2 then it should receive the following events: InitialEvent, 2, 3, 4, 5. 因此,如果我回到原始帖子:如果观察者在事件1,2之间启动订阅,那么它应该收到以下事件:InitialEvent,2、3、4、5。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.