Rx java 如何在不丢失发出的项目的情况下暂停可观察的项目?

Rx java 如何在不丢失发出的项目的情况下暂停可观察的项目?,rx-java,reactivex,Rx Java,Reactivex,我有一个可观察的,每秒都会发出滴答声: Observable.interval(0, 1, TimeUnit.SECONDS) .take(durationInSeconds + 1)); 我想暂停这个观测,这样它就不会发出数字,并根据需要恢复它 有一些问题: 根据ObservableJavadoc,interval操作符不支持背压 RxJava wiki关于有一节关于Callstack阻塞作为背压的流量控制替代方案: 处理生产过剩可观察对象的另一种方法是阻止调用堆栈(停止控制生产

我有一个
可观察的
,每秒都会发出滴答声:

Observable.interval(0, 1, TimeUnit.SECONDS)
    .take(durationInSeconds + 1));
我想暂停这个观测,这样它就不会发出数字,并根据需要恢复它

有一些问题:

  • 根据
    Observable
    Javadoc,
    interval
    操作符不支持背压
  • RxJava wiki关于有一节关于Callstack阻塞作为背压的流量控制替代方案:
处理生产过剩可观察对象的另一种方法是阻止调用堆栈(停止控制生产过剩可观察对象的线程)。这有违背Rx的“反应性”和非阻塞模型的缺点。但是,如果有问题的可观察对象位于可以安全阻止的线程上,那么这可能是一个可行的选项目前RxJava没有公开任何操作符来实现这一点。


是否有方法暂停可观察到的
间隔
?或者我应该通过一些背压支持来实现我自己的“滴答声”?

有很多方法可以做到这一点。例如,您仍然可以使用
interval()
并维护两个附加状态:例如布尔标志“暂停”和计数器

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()); 
}
公共静态最终可观测pausableInterval(
最终原子逻辑(暂停、长初始、长间隔、时间单位、调度程序){
最终AtomicLong计数器=新的AtomicLong();
返回可观察的间隔(初始、间隔、单位、调度程序)
.filter(勾选->!暂停.get())
.map(勾选->计数器.getAndIncrement());
}
然后,您只需调用paused.set(true/false)来暂停/恢复

编辑2016-06-04

上面的解决方案有一个小问题。 如果我们多次重用可观察实例,它将从上次取消订阅时的值开始。例如:

Observable<Long> o = pausableInterval(...)
List<Long> list1 = o.take(5).toList().toBlocking().single();
List<Long> list2 = o.take(5).toList().toBlocking().single();
Observable o=pausableInterval(…)
List list1=o.take(5.toList().toBlocking().single();
List 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);
  }
公共静态最终可观测pausableInterval(最终原子布尔暂停,最终长初始延迟,
最终长周期、时间单位、调度程序){
返回可观察间隔(初始延迟、周期、单位、调度程序)
.filter(勾选->!暂停.get())
.扫描((acc,勾选)->acc+1);
}
或者,如果您不希望依赖Java 8和lambdas,可以使用Java 6+兼容代码执行类似操作:


让我想起了你为什么要使用锁定操作员?没有托比,你就不能工作?或者如何在没有Toblock操作符的情况下订阅此事件?Toblock只是用于演示或单元测试。这只是为了确保您的单元测试不会在可观察对象完成之前退出。您可以像任何其他可观察对象一样异步运行它。