为什么我的RxJava Observable不会发出或完成,除非它被阻塞?

时间:2015-12-13 23:21:06

标签: java rx-java reactivex

背景

我有许多RxJava Observable(从Jersey客户端生成,或使用Observable.just(someObject)生成的存根)。所有这些都应该只发出一个值。我有一个组件测试,模拟了所有Jersey客户端并使用Observable.just(someObject),我看到了与运行生产代码时相同的行为。

我有几个类作用于这些可观察对象,执行一些计算(和一些副作用 - 我可能会在以后使它们成为直接返回值)并返回空的void observables。

有一次,在一个这样的课程中,我试图压缩我的几个源可观察量,然后映射它们 - 如下所示:

public Observable<Void> doCalculation() {
    return Observable.zip(
        getObservable1(),
        getObservable2(),
        getObservable3(),
        UnifyingObject::new
    ).concatMap(unifyingObject -> unifyingObject.processToNewObservable())
}

// in Unifying Object
public Observable<Void> processToNewObservable() {
    // ... do some calculation ...
    return Observable.empty();
}

然后将计算类组合在一起并等待:

// Wait for rule computations to complete
List<Observable<Void>> calculations = ...;
Observable.zip(calculations, results -> results)
        .toBlocking().lastOrDefault(null);

问题

麻烦的是,processToNewObservable()永远不会被执行。通过消除过程,我可以看到它是getObservable1()这就是麻烦 - 如果我用Observable.just(null)替换它,一切都按照我的想象执行(但是我想要一个真值的空值)。

重申一下,getObservable1()在生产代码中从Jersey客户端返回一个Observable,但该客户端是我的测试中返回Observable.just(someValue)的Mockito模拟。

研究

如果我将getObservable1()转换为阻塞,然后将第一个值包装在just()中,那么一切都按照我的想象执行(但我不想介绍阻塞步骤):< / p>

Observable.zip(
    Observable.just(getObservable1().toBlocking().first()),
    getObservable2(),
    getObservable3(),
    UnifyingObject::new
).concatMap(unifyingObject -> unifyingObject.processToNewObservable())

我的第一个想法是,也许其他东西消耗了我的observable发出的值,zip看到它已经完成,因此确定压缩它们的结果应该是一个空的可观察量。我已经尝试将.cache()添加到我认为相关的每个可观察源上,但是这并未改变行为。

我还尝试在zip之前在getObservable1上添加next / error / complete / finally处理程序(不将其转换为阻塞),但它们都没有执行:

getObservable1()
    .doOnNext(...)
    .doOnCompleted(...)
    .doOnError(...)
    .finallyDo(...);

Observable.zip(
    getObservable1(),
    getObservable2(),
    getObservable3(),
    UnifyingObject::new
).concatMap(unifyingObject -> unifyingObject.processToNewObservable())

问题

我对RxJava很新,所以我很确定我错过了一些基本的东西。问题是:我可以做些什么愚蠢的事情?如果从我到目前为止所说的不明显,我该怎么做才能帮助诊断问题?

3 个答案:

答案 0 :(得分:1)

Observable必须发出以启动链。您必须将您的管道视为Observable发出时将会发生什么的声明。

您没有分享实际观察到的内容,但Observable.just()会导致Observable立即发出包装对象。

答案 1 :(得分:0)

根据评论中的回复,getObservable中的任何一个都没有返回任何值,只是完成或Mockito模拟做错了。以下独立示例适用于我。你能检查一下并开始慢慢改变它,看看事情在哪里破裂吗?

Observable.zip(
        Observable.just(1),
        Observable.just(2),
        Observable.just(3),
        (a, b, c) -> new Integer[] { a, b, c })
 .concatMap(a -> Observable.from(a))
 .subscribe(System.out::println)
 ;

答案 2 :(得分:0)

注意:我在这里找不到令人满意的答案,所以我进一步挖掘并发现了一个小得多的复制案例,所以我在这里问了一个新问题:{{ 3}}

我已经找到了至少部分麻烦(并向所有试图回答的人道歉,我认为根据我的解释,你不会有太多机会。)

执行这些计算的各个类都返回Observable.empty()(根据我原始示例中的processToNewObservable())。据我所知,Observable.zip()没有订阅第N个可观察量,直到N-1th observable发出了一个值。

我的原始示例声称getObservable1()行为不端 - 实际上是轻微的不准确,后来在参数列表中可以观察到。根据我的理解,阻止它的原因,然后将该值转换为Observable再次起作用是因为阻止它并且首先强制执行它,并且我得到了我想要的副作用。

如果我将所有计算分类改为返回Observable.just(null),那么一切正常:所有计算类的最终zip()的可观测量都通过它们全部工作,因此所有预期的副作用都会发生。

从设计的角度来看,返回null Void似乎无疑是在做错事,但至少回答了这个问题。