Retrofit and RxJava: How to combine two requests and get access to both results?
Solution 1
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!"))
//...
}
Solution 2
The operator you are looking for is flatMap()
serviceA.getAllGeneros("movie","list","da0d692f7f62a1dc687580f79dc1e6a0")
.flatMap(genres -> serviceB.getAllMovies(genres.getId() ......))
Related videos on Youtube
David Hackro
https://github.com/David-Hackro https://github.com/TutorialesHackro https://www.reddit.com/user/hackro/ https://www.youtube.com/user/tutorialeshackro
Updated on June 04, 2022Comments
-
David Hackro almost 2 years
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(....); }
-
LordRaydenMK over 7 yearsYou need to call ServiceB with parameters from the result of the call to ServiceA?
-
David Hackro over 7 yearsyes exactly @LordRaydenMK
-
-
David Hackro over 7 yearsbut if my service return list objects and my service need id the each for object?
-
Maksim Ostrovidov over 7 yearsPlease provide code of
getAllGeneros
andgetAllMovies
methods. -
Maksim Ostrovidov over 7 yearsI can't understand what problem you are trying to solve with your code. Can you please provide a common explanation, e.g. "I am trying to show movies by given genres, passing genre id to..."
-
David Hackro over 7 yearsyes, i need passing id to getAllMovies() and combine Object Genre whit ResponseMovies, it's posible?
-
Maksim Ostrovidov over 7 yearsSo, according to my example - in
makeRequestToServiceB
you need to pass Genre ID from first response and make second request. -
Maksim Ostrovidov over 7 yearsTo achieve that all your code must be rewritten, so please take time to analyze my example.
-
David Hackro over 7 yearsthanks! work for me,please a favor,you can verify if my implementation it's correct? i updated the question whit the answerd
-
Maksim Ostrovidov over 7 yearsI checked your solution and it's correct. Glad to be helpful!
-
BabyishTank over 3 yearsHi, does this work if I have 2 or more observable?