Rx运算符。忽略,直到发出下一个

时间:2018-12-17 12:38:54

标签: java android kotlin rx-java reactivex

在我的应用程序中,我有耗时的逻辑,可以通过多种方式启动逻辑,比如说自动或由用户手动启动。

// Let's describe different event sources as relays
val autoStarts = PublishRelay.create<Unit>()
val manualStarts = PublishRelay.create<Unit>()
val syncStarts = PublishRelay.create<Unit>()

// This is my time consuming operation.
fun longOperation() = Observable.interval(10, TimeUnit.SECONDS).take(1).map { Unit }

val startsDisposable = Observable
        .merge(
                autoStarts.flatMap { Observable.just(Unit).delay(30, TimeUnit.SECONDS) },
                manualStarts
        )
        .subscribe(syncStarts) // merge emissions of both sources into one

val syncDisposable = syncStarts
        .concatMap {
            longOperation()
        }
        .subscribe(autoStarts) // end of long operation trigger start of auto timer

启动继电器可能会产生许多辐射。假设用户单击按钮进行手动启动,则剩余5个秒数,直到由计时器自动启动为止。如果很简单longOperation(),这两个事件都将导致flatMap开始。 我只希望一个线程在内部运行longOperation(),所以如果它现在正在运行并且尚未完成-忽略启动发射,无论如何完成都会导致计时器重启。

ConcatMap帮了我一半-它在“队列”中添加了longOperation(),因此它们被一个一个地处理,但是我怎么写这个来忽略任何进一步的开始,直到第一个完全完成?

2 个答案:

答案 0 :(得分:3)

您可以将flatMap()与额外的整数参数一起使用来限制并行度。

syncStarts
  .onBackpressureDrop()               // 1
  .flatMap(() -> longOperation(), 1)  // 2
  ...
  1. 丢弃flatMap()忙时发生的所有排放物。
  2. 数字1是flatMap()进行的订阅数,实际上是强制操作是顺序的。

上面完成了所需的功能。但是,您没有指定运行longOperation()后要发生的事情:是否要在此之后立即开始其他操作?如果是这样,则需要更改背压处理,以使最多一次排放排队。

答案 1 :(得分:0)

找到的解决方案:

val syncDisposable = syncStarts
    .concatMap {
        longOperation()
    }
    .take(1) // Complete after first longOperation() emit next item
    .repeat() // Resubscribe to this chain onCompleted so we continue to listen syncStarts ticks
    .subscribe(autoStarts) 

虽然有效,但看起来并不干净。尽管鲍勃的答案要求链为Flowable,但看起来更合乎逻辑。