我有Observable
每秒发出一次滴答声:
Observable.interval(0, 1, TimeUnit.SECONDS)
.take(durationInSeconds + 1));
我想暂停这个Observable,以便它停止发出数字,并按需恢复它。
有一些陷阱:
Observable
Javadoc,interval
运算符不支持背压处理过度生产的Observable的另一种方法是阻止callstack(停止管理过度生产的Observable的线程)。这样做的缺点是违背了“被动”和非阻塞模型RX。但是,如果有问题的Observable位于可以安全阻止的线程上,这可能是一个可行的选择。 目前,RxJava不会公开任何运营商来促进这一点。
有没有办法暂停interval
Observable?或者我应该使用一些背压支持来实现我自己的'滴答'Observable?
答案 0 :(得分:7)
有很多方法可以做到这一点。例如,你仍然可以使用interval()
并保持两个额外的状态:比如boolean flag" paused"和一个柜台。
public static final Observable<Long> pausableInterval(
final AtomicBoolean paused, long initial, long interval, TimeUnit unit, Scheduler scheduler) {
final AtomicLong counter = new AtomicLong();
return Observable.interval(initial, interval, unit, scheduler)
.filter(tick -> !paused.get())
.map(tick -> counter.getAndIncrement());
}
然后你只需要在某处调用paused.set(true / false)来暂停/恢复
编辑2016-06-04
上述解决方案存在一些问题。 如果我们多次重用observable实例,它将从最后一次取消订阅时的值开始。例如:
Observable<Long> o = pausableInterval(...)
List<Long> list1 = o.take(5).toList().toBlocking().single();
List<Long> list2 = o.take(5).toList().toBlocking().single();
虽然list1将是[0,1,2,3,4],但list2实际上是[5,6,7,8,9]。 如果不希望上述行为,则必须使观察者成为无状态。这可以通过scan()运算符来实现。 修订后的版本可能如下所示:
public static final Observable<Long> pausableInterval(final AtomicBoolean pause, final long initialDelay,
final long period, TimeUnit unit, Scheduler scheduler) {
return Observable.interval(initialDelay, period, unit, scheduler)
.filter(tick->!pause.get())
.scan((acc,tick)->acc + 1);
}
或者,如果您不希望依赖Java 8和lambdas,您可以使用Java 6+兼容代码执行此类操作: