在我的应用程序中,我有耗时的逻辑,可以通过多种方式启动逻辑,比如说自动或由用户手动启动。
// 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()
,因此它们被一个一个地处理,但是我怎么写这个来忽略任何进一步的开始,直到第一个完全完成?
答案 0 :(得分:3)
您可以将flatMap()
与额外的整数参数一起使用来限制并行度。
syncStarts
.onBackpressureDrop() // 1
.flatMap(() -> longOperation(), 1) // 2
...
flatMap()
忙时发生的所有排放物。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
,但看起来更合乎逻辑。