Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit and RxJava: How to combine two requests and get access to both results?

Tags:

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(....);     } 
like image 271
David Hackro Avatar asked Jan 22 '17 01:01

David Hackro


People also ask

What is the difference between Rxjava and retrofit?

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.


1 Answers

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.enter image description here

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!"))             //... } 
like image 175
Maksim Ostrovidov Avatar answered Oct 21 '22 08:10

Maksim Ostrovidov