我想异步执行2次网络调用 - 我正在使用Retrofit + RxJava来完成此任务。这个逻辑来自一个简单的Runner类来测试解决方案。注意:这主要涉及服务器端的RxJava。
我的代码如下所示:
public static void main(String[] args) throws Exception {
Api api = ...;
Observable.combineLatest(
api.getStates(),
api.getCmsContent(),
new Func2<List<States>, CmsContent, String>() {
@Override public String call(List<State> states, CmsContent content) {
...
return "PLACEHOLDER";
}
})
.observeOn(Schedulers.immediate())
.subscribeOn(Schedulers.immediate())
.subscribe(new Observer<String>() {
@Override public void onCompleted() {
System.out.println("COMPLETED");
}
@Override public void onError(Throwable e) {
System.out.println("ERROR: " + e.getMessage());
}
@Override public void onNext(String s) {
// I don't care what's returned here
}
});
}
三个问题:
Observable.combineLatest
是您想要异步执行多个REST调用并在所有调用完成后继续使用的最佳运算符吗?Func2
实施目前返回String
。执行2个API调用后,我将在Func2#call()
方法中处理结果。我不在乎返回什么 - 必须有一个更好的方法来处理这个问题 - 我是否正确?main
方法无法使用正确的Process finished with exit code 0
完成。可能导致代码挂起的原因是什么? 更新 - 2015-05-14
根据建议,我已将逻辑更改为以下内容:
public static void main(String[] args) throws Exception {
Api api = ...;
Observable.zip(
api.getStates(),
api.getCmsContent(),
new Func2<List<States>, CmsContent, Boolean>() {
@Override public Boolean call(List<State> states, CmsContent content) {
// process data
return true;
}
})
.subscribeOn(Schedulers.io())
.toBlocking()
.first();
}
这看起来像我正在寻找的解决方案。我将使用它一段时间,看看我是否遇到任何麻烦。
答案 0 :(得分:5)
1)如果您知道两条路径上都有一个值,那么它就像zip
一样好。
2)你想做什么?您将在Func2
中获得这对价值,如果您真的不关心使用onNext
旅行的内容,请返回您选择的价值。
3)Schedulers.immediate()
在某种意义上不是真正的调度程序,并且很容易出现相同的池死锁情况。你真的不需要使用它。如果要在完成异步工作之前阻止主线程,请使用toBlocking().first()
作为示例。
答案 1 :(得分:1)
1)不是最好使用zip()
。如果两个(或更多)api中的一个返回“慢”不同的结果/它具有缓存的本质,那么组合最新是好的。
2)Fun2有助于合并结果。在onNext()或onError()中处理结果更好(在架构方面)。您可以使用简单的Pair<T,Y>
类将结果从Func2传递给onNext()。
3)没有错。所述结果应在onNext()中处理,而不是在onComplete中处理。根据{{3}},结果仅在onNext()中传递(当然是corectly)。
希望那些帮助。
答案 2 :(得分:1)
我意识到我迟到了一年,但OP在2015-05-14发布的编辑不符合他原来的要求:
我想异步执行2次网络调用
Observables getStates
和getCmsContent
不会同时执行,除非他们单独订阅单独的线程。这是他的帖子中遗漏的一个关键点,之前的答案都没有提到它。
Observable.fromCallable(() -> doStuff())
.subscribeOn(Schedulers.computation());
正如@akarnokd所说,如果两个流都有单个值,zip
和combineLatest
的行为类似。合并函数将阻塞,直到getStates
和getCmsContent
都返回,但就像我上面所示,它们中的每一个都在不同的线程上并发执行。
另一种解决方案取决于List<States>
和CmsContent
到达时合并的能力。鉴于他的代码,显然有某种“数据持有者”(未显示),因为他返回的是Boolean
,而不是合并的数据。在下文中,forEach
同时执行。
Observable.just(api.getStates(), api.getCmsContent())
// subscribe on separate thread as shown previously
.flatMap(this::buildObservable)
.toBlocking()
// executes concurrently
.forEach(item -> {
// merge into "data holder"
});
当然,这段代码存在不强类型的问题,因此可以选择。