我的要求:
ResponseBody
个对象。我有什么:
Observable<ResponseBody> api1Call = api1.fetchData();
Observable<ResponseBody> api2Call = api2.fetchData();
Observable<ResponseBody> api3Call = api3.fetchData();
Observable.combineLatest(api1Call, api2Call, api3Call, new Func2<ResponseBody, ResponseBody, ResponseBody, Object>() {
@Override
public Object call(ResponseBody responseBody1, ResponseBody responseBody2, ResponseBody responseBody3) {
Logger.i("what does this do? - '%s', '%s', '%s'", responseBody1, responseBody2, responseBody3);
return null;
}
}).onErrorResumeNext(new Func1<Throwable, Observable<?>>() {
@Override
public Observable<?> call(Throwable throwable) {
Logger.e(throwable, "some error with one of the apis?");
return Observable.empty();
}
}).subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer<Object>() {
@Override
public void onCompleted() {
Logger.i("onCompleted");
}
@Override
public void onError(Throwable e) {
Logger.e(e, "onError");
}
@Override
public void onNext(Object o) {
Logger.i("onNext " + o);
}
});
我得到的输出:
some error with one of the apis?
// stacktrace of the error
onCompleted
我是RxJava的新手,非常困惑。我在StackOverflow上找到了一些答案,说zip
做了类似的事情,但它更符合我的要求。我猜测其中一个“组合”操作符+正确的异常处理将做我需要的。到目前为止,我们很难弄清楚
我正在使用的版本:
compile 'io.reactivex:rxjava:1.3.0'
compile 'io.reactivex:rxandroid:1.2.1'
compile 'com.squareup.retrofit2:adapter-rxjava:2.3.0'
答案 0 :(得分:6)
您无法通过combineLast
或zip
实现并行,rxjava
会在我的测试中按顺序执行并发出您的项目。
如果您的某个任务失败,则系统不会调用Func2#call
,而是会提交onError
。您甚至无法以这种方式获得其他成功任务的结果。
解决方案是flatMap
,它是rxjava
中实现并发的传统方式。它也符合您的其他要求。
这是一个小而完整的例子。
我使用简单的网站服务进行测试。
我使用Semaphore
等待完成所有任务,您可以完全忽略它。我将日志记录添加到http请求以便更好地理解,您也可以完全忽略它。
public interface WebsiteService {
@GET
Observable<ResponseBody> website(@Url String url);
}
然后我使用以下内容用rxjava
测试结果。
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BASIC);
Retrofit retrofit = new Retrofit.Builder().baseUrl("https://www.google.com")
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(new OkHttpClient.Builder().addInterceptor(loggingInterceptor).build())
.build();
WebsiteService websiteService = retrofit.create(WebsiteService.class);
final Semaphore s = new Semaphore(1);
try {
s.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
}
Observable<ResponseBody> first = websiteService.website("http://github.com");
Observable<ResponseBody> second = websiteService.website("http://stackoverflow.com");
Observable<ResponseBody> third = websiteService.website("http://notexisting.com");
final int numberOfCalls = 3; // testing for three calls
Observable.just(first, second, third)
.flatMap(new Function<Observable<ResponseBody>, ObservableSource<ResponseBody>>() {
@Override
public ObservableSource<ResponseBody> apply(@NonNull Observable<ResponseBody> responseBodyObservable) throws Exception {
return responseBodyObservable.subscribeOn(Schedulers.computation());
}
})
.subscribeOn(Schedulers.computation())
.subscribe(new Observer<ResponseBody>() {
private int currentDoneCalls = 0;
private void checkShouldReleaseSemaphore() {
if (currentDoneCalls >= numberOfCalls) {
s.release();
}
}
@Override
public void onSubscribe(@NonNull Disposable d) {
}
@Override
public void onNext(@NonNull ResponseBody responseBody) {
System.out.println("Retrofit call success " + responseBody.contentType());
synchronized (this) {
currentDoneCalls++;
}
checkShouldReleaseSemaphore();
}
@Override
public void onError(@NonNull Throwable e) {
System.out.println("Retrofit call failed " + e.getMessage());
synchronized (this) {
currentDoneCalls++;
}
checkShouldReleaseSemaphore();
}
@Override
public void onComplete() {
System.out.println("onComplete, All request success");
checkShouldReleaseSemaphore();
}
});
try {
s.acquire();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
System.out.println("All request done");
s.release();
}
我使用rxjava2
并改进adapter-rxjava2
进行测试。
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile 'io.reactivex.rxjava2:rxjava:2.1.0'
compile 'com.squareup.retrofit2:retrofit:2.3.0'
compile 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'
compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
来自github的RxJava2的介绍页面指出了实现并列论的实用方法。
实际上,RxJava中的并行性意味着运行独立流并将其结果合并回单个流中。运营商
flatMap
执行此操作...
虽然此示例基于RxJava2
,但操作flatMap
是
已存在于RxJava
。
答案 1 :(得分:1)
我认为在你的用例中,Zip运算符更合适
在这里你可以看到在主线程中运行,但如果你使用observerOn,它也可以让它在另一个线程中运行它们
/**
* Since every observable into the zip is created to subscribeOn a different thread, it´s means all of them will run in parallel.
* By default Rx is not async, only if you explicitly use subscribeOn.
*/
@Test
public void testAsyncZip() {
scheduler = Schedulers.newThread();
scheduler1 = Schedulers.newThread();
scheduler2 = Schedulers.newThread();
long start = System.currentTimeMillis();
Observable.zip(obAsyncString(), obAsyncString1(), obAsyncString2(), (s, s2, s3) -> s.concat(s2)
.concat(s3))
.subscribe(result -> showResult("Async in:", start, result));
}
private Observable<String> obAsyncString() {
return Observable.just("")
.observeOn(scheduler)
.doOnNext(val -> {
System.out.println("Thread " + Thread.currentThread()
.getName());
})
.map(val -> "Hello");
}
private Observable<String> obAsyncString1() {
return Observable.just("")
.observeOn(scheduler1)
.doOnNext(val -> {
System.out.println("Thread " + Thread.currentThread()
.getName());
})
.map(val -> " World");
}
private Observable<String> obAsyncString2() {
return Observable.just("")
.observeOn(scheduler2)
.doOnNext(val -> {
System.out.println("Thread " + Thread.currentThread()
.getName());
})
.map(val -> "!");
}
您可以在此处查看更多示例https://github.com/politrons/reactive
答案 2 :(得分:1)
您可以使用Observable.mergeDelayError(api1Call, api2Call, api3Call)
。
Bonus :您还可以指定可以同时运行多少个最大并行调用。例如:
Observable
.mergeDelayError(Observable.from(api1Call, api2Call, api3Call), 5)
。
答案 3 :(得分:0)
combineLatest
或zip
运算符(对于Retrofit调用),则每次调用只会发出一个项目。因此,两个运营商都将等待所有呼叫完成。所以,我们不需要担心这一点。有关详情,请查看combineLatest和zip。 1 call fail
,则会抛出此错误,不会发出任何组合项。但是1 call fail
是http request fail
,当3个调用完成时,流总是会发出一个项目。我们无法在此使用combineLast
或zip
运算符。答案 4 :(得分:0)
感谢@TinTran和this,这是正确的解决方案:
(我现在不能提出Retrofit Observables的确切语法,但这不重要,逻辑仍然是相同的改造)
Observable.mergeDelayError(getData1(), getData2()).doAfterTerminate(new Action0() {
@Override
public void call() {
Logger.i("end of all streams");
tvTheText.setText("all streams finished");
}
}).subscribe(new PrintSubscriber<>("merge" +
" delay w error"));
观察者(改造者应该以同样的方式工作):
private Observable<String> getData1() {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> singleSubscriber) {
try {
long responseTime = 120 + new Random().nextInt(30);
Thread.sleep(responseTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleSubscriber.onNext("data 1");
singleSubscriber.onCompleted();
}
}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io());
}
private Observable<String> getData2() {
return Observable.create(new Observable.OnSubscribe<String>() {
@Override
public void call(Subscriber<? super String> singleSubscriber) {
try {
long responseTime = 100 + new Random().nextInt(19);
Thread.sleep(responseTime);
} catch (InterruptedException e) {
e.printStackTrace();
}
singleSubscriber.onError(new Exception());// this one never blocks the other Observables' streams
}
}).observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io());
}
输出日志:
10-24 15:27:23.335 D: ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
10-24 15:27:23.335 D: │ Thread: main
10-24 15:27:23.335 D: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
10-24 15:27:23.335 D: │ SafeSubscriber.onNext (SafeSubscriber.java:134)
10-24 15:27:23.335 D: │ PrintSubscriber.onNext (PrintSubscriber.java:32)
10-24 15:27:23.335 D: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
10-24 15:27:23.336 D: │ merge delay w error - onNext - data 1
10-24 15:27:23.336 D: └────────────────────────────────────────────────────────────────────────────────────────────────────────────────
10-24 15:27:23.342 V: ⇢ onError(e=java.lang.Exception)
10-24 15:27:23.342 V: ⇠ onError [0ms]
10-24 15:27:23.343 I: ┌────────────────────────────────────────────────────────────────────────────────────────────────────────────────
10-24 15:27:23.343 I: │ Thread: main
10-24 15:27:23.343 I: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
10-24 15:27:23.343 I: │ OperatorDoAfterTerminate$1.callAction (OperatorDoAfterTerminate.java:73)
10-24 15:27:23.343 I: │ MainActivity$1.call (MainActivity.java:37)
10-24 15:27:23.343 I: ├┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄
10-24 15:27:23.344 I: │ end of all streams
10-24 15:27:23.344 I: └────────────────────────────────────────────────────────────────────────────────────────────────────────────────