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(....); }
Rx gives you a very granular control over which threads will be used to perform work in various points within a stream. To point the contrast here already, basic call approach used in Retrofit is only scheduling work on its worker threads and forwarding the result back into the calling thread.
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!")) //... }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With