仅在链中的Observable发出事件后才接受事件

时间:2016-09-28 20:07:59

标签: rx-java reactive-programming

以下是链:observableOne.flatMap(event -> observableTwo).subscribe()

我希望在第一次发出事件时从observableOne中获取事件,然后忽略此Observable中的所有其他事件,直到observableTwo发出值为止,完成或完成错误。值得一提的是,我最终对第二个Observable的事件感兴趣。

上下文就像是,Button点击了一个事件被触发,这是ObservableOne。触发事件触发ObservableTwo,让我们说它是一系列网络操作。因此,我希望在执行网络操作时忽略所有按钮单击。

3 个答案:

答案 0 :(得分:0)

要控制flatMap所做的请求金额,请使用特殊的重载:

observableOne
  .doOnRequest(System.out::println)
  .flatMap(event -> observableTwo, 1)
  .flatMap(event -> observableThree, 1)
.subscribe()

如果您的来源observableOneobservableTwoobservableThree是同步的,那么这不是必需的,但对于异步来源,这应该可以胜任。

答案 1 :(得分:0)

[Edit2]问题已经改变,所以我调整了答案+实际上给出了正确的答案

我没有看到其他方式,而不是状态标志:

AtomicBoolean progress = new AtomicBoolean();
observableOne
        .filter(event -> !progress.get())
        .flatMap(event ->
                observableTwo
                        .doOnSubscribe(() -> progress.set(true))
                        .doOnTerminate(() -> progress.set(false))
        )
        .subscribe();

如果发生错误,您的订阅将被取消,即使再次点击该按钮,您也不会再收到任何活动。

如果这不是你想要的,你可以:

  • 重新订阅错误回调

    private void bindRemoteCalls() {
        if (mySubscription != null) mySubscription.unsubscribe();
        AtomicBoolean progress = new AtomicBoolean();
        mySubscription = observableOne
            .filter(event -> !progress.get())
            .flatMap(event ->
                    observableTwo
                            .doOnSubscribe(() -> progress.set(true))
                            .doOnTerminate(() -> progress.set(false))
            )
            .flatMap(event -> observableTwo, 1)
            .subscribe(
                data -> handleResponse(data),
                error -> {
                    handleError(error);
                    bindRemoteCalls();
                }
            );
    }
    
  • 使用onErrorReturn()(与doOnError()结合使用来实际做点什么)

    AtomicBoolean progress = new AtomicBoolean();
    observableOne
        .filter(event -> !progress.get())
        .flatMap(event ->
                observableTwo
                        .doOnSubscribe(() -> progress.set(true))
                        .doOnTerminate(() -> progress.set(false))
                        .doOnError(error -> handleError(error))
                        .onErrorReturn(null)
                        .filter(data -> data != null)
        )
        .subscribe(data -> handleResponse(data));
    

如果需要,请记住将subscribeOn() / observeOn()与正确的调度程序一起使用。

请考虑使用switchMap()代替flatMap() - >如果再次按下该按钮,则取消前一个呼叫(取消订阅),然后启动一个新呼叫。或者以Rx术语说:observableTwo以前的订阅已取消订阅并且会形成新的订阅。

如果在取消订阅时禁用按钮并在终止时启用它,则可以通过使按钮不可点击轻松获得相同的结果。

答案 2 :(得分:0)

您可以使用Flowable而不是Observable,然后可以通过设置observableTwo使用背压来达到所需的效果(直到maxConcurrency终止的丢弃事件)从flatMap1

observableOne
    .toFlowable(BackpressureStrategy.DROP)
    .flatMap(event -> observableTwo.toFlowable(BackpressureStrategy.ERROR), 1)
    .subscribe();

我发布了similar question here

结果证明,akarnokd在RxJava2Extensions库中也有一个专门用于此目的的ObservableTransformer。可以这样使用:

observableOne
    .compose(ObservableTransformers.flatMapDrop(event -> observableTwo))
    .subscribe();