我需要创建并发网络请求。根据这些请求的结果,可能会启动更多请求。
我希望在所有请求完成后获得单个Completable,并且不需要创建进一步的请求。
我的问题是,是否可以使用以下代码段实现:
return Completable.defer(() -> {
startRequests();
return Observable.merge(requestSubject.asObservable()).toCompletable();
});
在此示例中,startRequest会将网络请求(Retrofit)添加到requestSubject,即PublishSubject<Observable<SomeResponse>>
。
具体而言,我希望网络请求一旦订阅就在IO调度程序上启动,并且返回的Completable要完成,直到我在其中一个请求的onNext中调用requestSubject.onComplete()
。
我还没弄清楚如何在不执行请求两次的情况下处理请求的响应(每次订阅都要进行Retrofit请求)。
它是以这种方式工作,还是有更好的方法来实现我想要的东西?谢谢!
答案 0 :(得分:2)
只需使用flatmap()
并将其转换为Completable
。
这是一个(模拟)执行网络请求的示例,该请求返回io
池上的2个项目,然后它对computation
池中的这些项执行计算,并行:
@Test
public void foo() throws Exception {
Observable.range(1, 10)
.flatMap(this::getNItemsFromNetwork)
.flatMap(this::asyncCompuatation)
.ignoreElements()
.subscribe(() -> System.out.println("onComplete"),
(t) -> System.out.println("onError"));
Thread.sleep(10000);
}
Observable<String> getNItemsFromNetwork(int count) {
return Observable.just(count)
.subscribeOn(Schedulers.io())
.doOnNext(i -> System.out.println("Executing request for " + count + " on thread: " + Thread.currentThread()))
.flatMap(number -> Observable.just("Item nr " + number + ".1", "Item nr " + number + ".2"))
.delay(random.nextInt(1000), TimeUnit.MILLISECONDS);
}
Observable<String> asyncCompuatation(String string) {
return Observable.just(string)
.subscribeOn(Schedulers.computation())
.delay(random.nextInt(1000), TimeUnit.MILLISECONDS)
.doOnNext(number -> System.out.println("Computing " + number + " on thread: " + Thread.currentThread()));
}
输出验证:
Executing request for 7 on thread: Thread[RxCachedThreadScheduler-7,5,main]
Executing request for 6 on thread: Thread[RxCachedThreadScheduler-6,5,main]
Executing request for 5 on thread: Thread[RxCachedThreadScheduler-5,5,main]
Executing request for 1 on thread: Thread[RxCachedThreadScheduler-1,5,main]
Executing request for 4 on thread: Thread[RxCachedThreadScheduler-4,5,main]
Executing request for 3 on thread: Thread[RxCachedThreadScheduler-3,5,main]
Executing request for 8 on thread: Thread[RxCachedThreadScheduler-8,5,main]
Executing request for 2 on thread: Thread[RxCachedThreadScheduler-2,5,main]
Executing request for 9 on thread: Thread[RxCachedThreadScheduler-9,5,main]
Executing request for 10 on thread: Thread[RxCachedThreadScheduler-10,5,main]
Computing Item nr 7.1 on thread: Thread[RxComputationThreadPool-5,5,main]
Computing Item nr 10.2 on thread: Thread[RxComputationThreadPool-2,5,main]
Computing Item nr 6.2 on thread: Thread[RxComputationThreadPool-1,5,main]
Computing Item nr 3.1 on thread: Thread[RxComputationThreadPool-7,5,main]
Computing Item nr 4.1 on thread: Thread[RxComputationThreadPool-7,5,main]
Computing Item nr 3.2 on thread: Thread[RxComputationThreadPool-1,5,main]
Computing Item nr 6.1 on thread: Thread[RxComputationThreadPool-7,5,main]
Computing Item nr 2.1 on thread: Thread[RxComputationThreadPool-7,5,main]
Computing Item nr 5.2 on thread: Thread[RxComputationThreadPool-2,5,main]
Computing Item nr 5.1 on thread: Thread[RxComputationThreadPool-5,5,main]
Computing Item nr 7.2 on thread: Thread[RxComputationThreadPool-2,5,main]
Computing Item nr 2.2 on thread: Thread[RxComputationThreadPool-1,5,main]
Computing Item nr 10.1 on thread: Thread[RxComputationThreadPool-5,5,main]
Computing Item nr 9.1 on thread: Thread[RxComputationThreadPool-5,5,main]
Computing Item nr 4.2 on thread: Thread[RxComputationThreadPool-1,5,main]
Computing Item nr 9.2 on thread: Thread[RxComputationThreadPool-2,5,main]
Computing Item nr 8.1 on thread: Thread[RxComputationThreadPool-5,5,main]
Computing Item nr 8.2 on thread: Thread[RxComputationThreadPool-2,5,main]
Computing Item nr 1.1 on thread: Thread[RxComputationThreadPool-7,5,main]
Computing Item nr 1.2 on thread: Thread[RxComputationThreadPool-1,5,main]
onComplete
答案 1 :(得分:1)
好的,不确定我的问题是否100%正确,但这里是我要做的事情的粗略草图......我相信你希望Subject
作为缓存的中间级别当你打电话取消订阅时,不要打断实际请求。
1)假设您有2个Retrofit Observables。
2)在startRequests()
中,您需要订阅它们(在您需要的某些调度程序上),应用doOnNext
运算符并将数据委托给subject
。因此,主题将从API获得2个滴答数据。
3)订阅您的主题,您将收到2个数据滴答。
基本上没有必要等待完成,你只需要接收N个onNext ticks。 但是如果你想要一些指标表明所有请求都已完成,你可以例如合并所有改进的observable,并将所有事件委托给subject,这样它最终会收到N个onNext ticks和onComplete。
答案 2 :(得分:0)
我认为使用Subjects
是不必要的并发症。
你只需使用flatMap()
并使用Completable
转移到toCompletable()
,你没有提到你的特定循环是如何工作的,但假设你有一些循环列表查询就像这样,startRequest(data)
返回Retrofit
查询Observable
:
List<Data> list = ...;
Observable.from(list)
.flatMap(new Func1<Data, Observable<Result>>() {
@Override
public Observable<Result> call(Data data) {
return startRequest(data);
}
}).toCompletable();
关于您的第二个请求,执行更多请求取决于结果,在这种情况下,您可能希望使用toList()
收集所有请求,您将收到一个onNext()
通知,然后您可以对其进行过滤所有,并在您想要请求更多数据时获取发出项目的Observable
:
List<Data> list =...;
Observable.from(list)
.flatMap(new Func1<Data, Observable<Result>>() {
@Override
public Observable<Result> call(Data data) {
return startRequest(data);
}
})
.toList()
.filter(new Func1<List<Result>, Boolean>() {
@Override
public Boolean call(List<Result> results) {
return shouldRequestMore(results);
}
});