Retrofit和RxJava:如何组合两个请求并获得对这两个结果的访问权限? [英] Retrofit and RxJava: How to combine two requests and get access to both results?
问题描述
我需要提出两项服务请求并将结果合并:
ServiceA()=> [{id:1, name:title},{id:1,name:title}]
ServiceB( id
)=> {field:value,field1:value}
目前,我已设法合并结果,但我需要将 id
作为参数传递给 ServiceB 并获取第一个结果的访问权限。
到目前为止我尝试了什么:
Retrofit repo = new Retrofit .Builder()
.baseUrl(https://api.themoviedb.org/3/genre/)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory。 create())
.build();
Observable< GenerosResponse>类型= repo
.create(services.class)
.getAllGeneros(movie,list,da0d692f7f62a1dc687580f79dc1e6a0)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
Observable< ResponseMovies> Movies = repo
.create(services.class)
.getAllMovies(28,movies,da0d692f7f62a1dc687580f79dc1e6a0,12)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
Observable< CollectionsMovies> combined = Observable.zip(流派,电影,新Func2< GenerosResponse,ResponseMovies,CollectionsMovies>(){
@Override
public CollectionsMovies call(GenerosResponse generosResponse,ResponseMovies responseMovies){
return new CollectionsMovies (generosResponse,responseMovies);
}
});
合计。
subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
修改
解决方案根据@Maxim Ostrovidov的回答:
private Observable< GenerosResponse> makeRequestToServiceA(){
return service.getAllGeneros(movie,list,da0d692f7f62a1dc687580f79dc1e6a0); //一些网络电话
}
private Observable< ResponseMovies> makeRequestToServiceB(流派类型){
返回service.getAllMovies(genre.getId(),movies,da0d692f7f62a1dc687580f79dc1e6a0,created_at.asc); //基于ServiceA的响应的一些网络调用
}
void doTheJob(){
makeRequestToServiceA()
.flatMap(userResponse - > Observable.just(userResponse.getGenres()))//从响应中获取列表
.flatMapIterable(baseDatas - > baseDatas)
.flatMap(new Func1< Genre,Observable<?extends ResponseMovies>> (){
@Override
public Observable<?extends ResponseMovies> call(Genre genre){
return makeRequestToServiceB(genre);
}
} ,新的Func2<类型,ResponseMovies,CollectionsMovies>(){
@Override
public CollectionsMovies call(流派类型,ResponseMovies responseMovies){
返回新的CollectionsMovies(流派,responseMovies) ;
}
})。
subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(....);
}
据我所知 - 你需要根据另一个请求的结果发出请求并合并两个结果。为此,您可以使用此 flatMap
运算符变体:
简单示例指出如何重写代码:
private Observable< String> makeRequestToServiceA(){
return Observable.just(serviceA response); //一些网络电话
}
private Observable< String> makeRequestToServiceB(String serviceAResponse){
return Observable.just(serviceB response); //基于ServiceA的响应的一些网络调用
}
private void doTheJob(){
makeRequestToServiceA()
.flatMap(new Func1< String,Observable< ?extends String>>(){
@Override
public Observable<?extends String> call(String responseFromServiceA){
//根据ServiceA的响应发出第二个请求
返回makeRequestToServiceB(responseFromServiceA);
}
},new Func2< String,String,Observable< String>>(){
@Override
public Observable< String> call( String responseFromServiceA,String responseFromServiceB){
//合并结果
返回Observable.just(这里是合并结果!);
}
})
//应用调度程序,订阅等
}
使用lambdas:
private void doTheJob(){
makeRequestToServiceA( )
.flatMap(responseFromServiceA - > makeRequestToServiceB(responseFromServiceA),
(responseFromServiceA,responseFromServiceB) - > Observable.just(这里是合并结果!))
// ... ...
}
I need to make two requests for services and combine it results:
ServiceA() => [{"id":1,"name":"title"},{"id":1,"name":"title"}]
ServiceB(id
) => {"field":"value","field1":"value"}
Currently, I have managed to combine the results, but I need to pass id
as a parameter to the ServiceB and get access to the first result.
What I tried so far:
Retrofit repo = new Retrofit.Builder()
.baseUrl("https://api.themoviedb.org/3/genre/")
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
Observable<GenerosResponse> Genres = repo
.create(services.class)
.getAllGeneros("movie","list","da0d692f7f62a1dc687580f79dc1e6a0")
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
Observable<ResponseMovies> Movies = repo
.create(services.class)
.getAllMovies("28","movies","da0d692f7f62a1dc687580f79dc1e6a0",12)
.subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread());
Observable<CollectionsMovies> combined = Observable.zip(Genres, Movies, new Func2<GenerosResponse, ResponseMovies, CollectionsMovies>() {
@Override
public CollectionsMovies call(GenerosResponse generosResponse, ResponseMovies responseMovies) {
return new CollectionsMovies(generosResponse, responseMovies);
}
});
combined.
subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(...);
Edit
Solution according to @Maxim Ostrovidov's answer:
private Observable<GenerosResponse> makeRequestToServiceA() {
return service.getAllGeneros("movie","list","da0d692f7f62a1dc687580f79dc1e6a0"); //some network call
}
private Observable<ResponseMovies> makeRequestToServiceB(Genre genre) {
return service.getAllMovies(genre.getId(),"movies","da0d692f7f62a1dc687580f79dc1e6a0","created_at.asc"); //some network call based on response from ServiceA
}
void doTheJob() {
makeRequestToServiceA()
.flatMap(userResponse -> Observable.just(userResponse.getGenres())) //get list from response
.flatMapIterable(baseDatas -> baseDatas)
.flatMap(new Func1<Genre, Observable<? extends ResponseMovies>>() {
@Override
public Observable<? extends ResponseMovies> call(Genre genre) {
return makeRequestToServiceB(genre);
}
}, new Func2<Genre, ResponseMovies, CollectionsMovies>() {
@Override
public CollectionsMovies call(Genre genre, ResponseMovies responseMovies) {
return new CollectionsMovies(genre,responseMovies);
}
}).
subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(....);
}
As I understand - you need to make a request based on result of another request and combine both results. For that purpose you can use this flatMap
operator variant: Observable.flatMap(Func1 collectionSelector, Func2 resultSelector)
Returns an Observable that emits the results of a specified function to the pair of values emitted by the source Observable and a specified collection Observable.
Simple example to point you how to rewrite your code:
private Observable<String> makeRequestToServiceA() {
return Observable.just("serviceA response"); //some network call
}
private Observable<String> makeRequestToServiceB(String serviceAResponse) {
return Observable.just("serviceB response"); //some network call based on response from ServiceA
}
private void doTheJob() {
makeRequestToServiceA()
.flatMap(new Func1<String, Observable<? extends String>>() {
@Override
public Observable<? extends String> call(String responseFromServiceA) {
//make second request based on response from ServiceA
return makeRequestToServiceB(responseFromServiceA);
}
}, new Func2<String, String, Observable<String>>() {
@Override
public Observable<String> call(String responseFromServiceA, String responseFromServiceB) {
//combine results
return Observable.just("here is combined result!");
}
})
//apply schedulers, subscribe etc
}
Using lambdas:
private void doTheJob() {
makeRequestToServiceA()
.flatMap(responseFromServiceA -> makeRequestToServiceB(responseFromServiceA),
(responseFromServiceA, responseFromServiceB) -> Observable.just("here is combined result!"))
//...
}
这篇关于Retrofit和RxJava:如何组合两个请求并获得对这两个结果的访问权限?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!