我有许多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很新,所以我很确定我错过了一些基本的东西。问题是:我可以做些什么愚蠢的事情?如果从我到目前为止所说的不明显,我该怎么做才能帮助诊断问题?
答案 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似乎无疑是在做错事,但至少回答了这个问题。