在一段时间内没有发出项目后,寻找一种简洁的方法来转换源Observable
以发出单个null
(或哨兵值)。
例如,如果源observable发出1, 2, 3
,则在发出4, 5, 6
之前停止发射10秒钟我希望发出的项目为1, 2, 3, null, 4, 5, 6
。
用例用于在UI中显示值,如果最后一个值是陈旧/过时,显示的值应变为短划线-
或N/A
。
我查看了timeout
运算符,但是当超时发生时它会终止Observable
,这是不可取的。
使用RxJava。
答案 0 :(得分:2)
基于akarnokd's answer和an answer in a similar question,另一种实现方式:
如果您正在寻找一个值来表明排放之间的时间间隔:
final TestScheduler scheduler = new TestScheduler();
final TestSubject<Integer> subject = TestSubject.create(scheduler);
final TestSubscriber<Integer> subscriber = new TestSubscriber<>();
final long duration = 100;
final Observable<Integer> timeout = Observable.just(-1).delay(duration, TimeUnit.MILLISECONDS, scheduler)
.concatWith(Observable.never())
.takeUntil(subject)
.repeat();
subject.mergeWith(timeout).subscribe(subscriber);
subject.onNext(1, 0);
subject.onNext(2, 100);
subject.onNext(3, 200);
scheduler.advanceTimeBy(200, TimeUnit.MILLISECONDS);
scheduler.advanceTimeBy(300, TimeUnit.MILLISECONDS);
subject.onNext(4, 0);
subject.onNext(5, 100);
subject.onNext(6, 200);
scheduler.advanceTimeBy(200, TimeUnit.MILLISECONDS);
subscriber.assertNoTerminalEvent();
subscriber.assertReceivedOnNext(Arrays.asList(1, 2, 3, -1, 4, 5, 6));
如果您希望在源观察源在一段时间内不发光后继续接收值:
final TestScheduler scheduler = new TestScheduler();
final TestSubject<Integer> subject = TestSubject.create(scheduler);
final TestSubscriber<Integer> subscriber = new TestSubscriber<>();
final long duration = 100;
final Observable<Integer> timeout = Observable.interval(duration, duration, TimeUnit.MILLISECONDS, scheduler)
.map(x -> -1)
.takeUntil(subject)
.repeat();
subject.mergeWith(timeout).subscribe(subscriber);
subject.onNext(1, 0);
subject.onNext(2, 100);
subject.onNext(3, 200);
scheduler.advanceTimeBy(200, TimeUnit.MILLISECONDS);
scheduler.advanceTimeBy(300, TimeUnit.MILLISECONDS);
subject.onNext(4, 0);
subject.onNext(5, 100);
subject.onNext(6, 200);
scheduler.advanceTimeBy(200, TimeUnit.MILLISECONDS);
subscriber.assertNoTerminalEvent();
subscriber.assertReceivedOnNext(Arrays.asList(1, 2, 3, -1, -1, -1, 4, 5, 6));
差异是timeout
可观察到的以及是否经常发生。
您可以根据需要将-1
替换为null
。
使用Java 1.8.0_72
使用RxJava 1.0.17测试上述所有内容。
答案 1 :(得分:1)
您可以通过稍微复杂的publish-amb-timer设置来实现此目的:
PublishSubject<Integer> ps = PublishSubject.create();
TestScheduler s = Schedulers.test();
TestSubscriber<Integer> ts = new TestSubscriber<>();
ps.publish(o ->
o.take(1).ambWith(Observable.timer(10, TimeUnit.SECONDS, s).map(v -> (Integer)null))
.repeat().takeUntil(o.ignoreElements())
).subscribe(ts);
ps.onNext(1);
ps.onNext(2);
ps.onNext(3);
s.advanceTimeBy(15, TimeUnit.SECONDS);
ps.onNext(4);
ps.onNext(5);
ps.onNext(6);
ps.onCompleted();
ts.assertValues(1, 2, 3, null, 4, 5, 6);
发生的消息是源已发布,因此您可以从中逐个获取项目或计时器事件,确保最快的获胜并使用下一个值重复它,所有这些都不会一直重新订阅原始来源
编辑修复了上游完成后重复()进入无限循环的情况。