为什么我的RxJava Observable只向第一个消费者发射?

时间:2015-12-15 22:59:33

标签: java reactive-programming rx-java

有人可以解释为什么下面的测试失败了吗?

public class ObservableTest {
    @Test
    public void badObservableUsedTwiceDoesNotEmitToSecondConsumer() {
        // Any simpler observable makes the test pass
        Observable<Integer> badObservable = Observable.just(1)
                .zipWith(Observable.just(2), (one, two) -> Observable.just(3))
                .flatMap(observable -> observable);

        ObservableCalculator calc1 = new ObservableCalculator(badObservable);
        ObservableCalculator calc2 = new ObservableCalculator(badObservable);

        // zipping causes the failure
        // Calling calculate().toBlocking().subscribe() on each calc passes
        // Observable.from(listOfCalcs).flatMap(calc -> calc.calculate()) passes
        Observable.zip(ImmutableList.of(calc1.calculate(), calc2.calculate()), results -> results)
                .toBlocking()
                .subscribe();

        assertThat(calc1.hasCalculated).isTrue();
        assertThat(calc2.hasCalculated).isTrue(); // this fails
    }

    private static class ObservableCalculator {
        private final Observable<?> observable;

        public boolean hasCalculated = false;

        public ObservableCalculator(Observable<?> observable) {
            this.observable = observable;
        }

        public Observable<Void> calculate() {
            return observable.concatMap(o -> {
                hasCalculated = true;
                // returning Observable.just(null) makes the test pass
                return Observable.empty();
            });
        }
    }
}

我试图进一步简化“坏”观察,但找不到任何我可以删除的东西以使其更简单。

我目前的理解是,它是一个Observable(无论它是如何构造的),应该发出一个值然后完成。然后我们基于Observable创建一个对象的两个类似实例,并在那些使用Observable的对象上调用一个方法,记下这样做,然后返回Observable.empty()。

任何人都可以解释为什么使用这个observable导致测试失败(当使用更简单的observable导致测试通过时)?

也可以通过串行调用calculate()。toBlocking()。subscribe()而不是使用zip来进行测试,或者使计算返回Observable.just(null)。这让一些对我有意义(如果calc1为空,zip将不会订阅calc2,因为在那种情况下zip可能永远不会产生任何东西),但不完全意义(我不明白为什么压缩对于更简单的badObservable版本,行为不一样 - 不管输入如何,calculate()方法仍然返回空白。

1 个答案:

答案 0 :(得分:1)

如果您使用某些内容压缩空源,则操作员会检测到它不再产生任何值,并取消其所有来源的订阅。有一个zip和merge的混合,并且merge严格取消订阅:它根本不发出值3,因此concatMap也不会调用第二个源的映射函数。