RxJava:仅在给定时间段内的第一个项目时发出

时间:2017-07-06 14:23:36

标签: rx-java rx-java2

我想以这样的方式转换我的源Flowable,即只要它们是指定时间段内的第一个项目,事件才会发生。

也就是说,我希望第一个项目通过然后删除所有后续项目,直到有一段时间,比如10秒,其中没有上游事件到达。

请注意,这不是

  • debounce:如果没有其他一个项目持续10秒钟,这会发出每个项目 - 但这会迫使第一个项目延迟10秒。我想立即发出第一个项目。
  • throttleFirst:这将发出第一个项目,然后在第一个项目之后丢弃所有后续项目10秒。我希望在每个上游项目之后重置阻塞时段。

我现在已经解决了这个问题:

source
  .flatMap { Flowable.just(1).concatWith(Flowable.just(-1).delay(10, TimeUnit.SECONDS)) }
  .scan(0, { x, y -> x + y })
  .map { it > 0 }
  .distinctUntilChanged()
  .filter { it }

注意:我并不关心source中的实际项目,只关注它们 - 但当然,我可以将项目与Pair一起包裹在1中1}}或-1)。

是否有更简单的方法使用内置的RxJava(2)运算符来实现相同的目标?

2 个答案:

答案 0 :(得分:2)

可以使用switchMap一次仅订阅一个Flowable并使用布尔值检查是否必须发出的事实:

class ReduceThrottle<T>(val period: Long, val unit: TimeUnit) : FlowableTransformer<T, T> {
    override fun apply(upstream: Flowable<T>): Publisher<T> {
        return Flowable.defer {
            val doEmit = AtomicBoolean(true)

            upstream.switchMap { item ->
                val ret = if (doEmit.compareAndSet(true, false)) {
                    // We haven't emitted in the last 10 seconds, do the emission
                    Flowable.just(item)
                } else {
                    Flowable.empty()
                }

                ret.concatWith(Completable.timer(period, unit).andThen(Completable.fromAction {
                    // Once the timer successfully expires, reset the state
                    doEmit.set(true)
                }).toFlowable())
            }
        }
    }
}

然后,只需应用变压器:source.compose(ReduceThrottle(10, TimeUnit.SECONDS))

答案 1 :(得分:-1)

这可能会做你需要的事情

source.debounce(item -> Observable.timer(10,TimeUnit.SECONDS))