9

I'm new to RXJava and i'm having trouble understanding how to chain together the result of API calls.

I'm making two API calls using retrofit, A and B, which both return an observable List of objects. Both API calls are independent so I want to make both at the same time, but to achieve my final result, I need to first take the result of A, do some work, then combine that with the result of B to populate my list adapter.

  • Make API Call A
  • Make API Call B
  • Take A's result and create result X
  • Take Result of B + X and populate adapter

    @GET("/{object_id}/object_a")
        Observable<List<Object_A>> getObjectAList(
            @Path("object_id") long object_id);
    
    
    @GET("/{object_id}/object_b")
        Observable<List<Object_B>> getObjectBList(
            @Path("object_id") long object_id);
    

This is where I get lost trying to use RX java. I can take the result of api call A and do my work but I'm not sure how to take the result I just generated and combine it with API Call B.

aService. getObjectAList(object_a.getID())
            .subscribeOn(AndroidSchedulers.mainThread())
            .observeOn(AndroidSchedulers.main)
            .subscribe(new Action1<List<Object_A>>() {

                @Override
                public void call(List<Section> sections) {
                    // Do Stuff Here...
                    // Now i need to take this result and combine it with API Call B...
                }
            });

I want to make both API calls at the same time, but i'm not sure how to chain together and combine API calls. Any help is appreciative.

user3169791
  • 351
  • 2
  • 3
  • 9

3 Answers3

11

Something like this?

Observable
        // make api call for A list and B list
        .combineLatest(getObjectAList(), getObjectBList(), new Func2<List<Object_A>, List<Object_B>, Object>() {
            @Override
            public Object call(List<Object_A> o, List<Object_B> o2) {
                // Do what you need to do in the background thread
                List x = createX(o);
                List y = createY(x, o2);
                return y;
            }
        })
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(new Observer<Object>() {
            @Override
            public void onCompleted() {

            }

            @Override
            public void onError(Throwable e) {

            }

            @Override
            public void onNext(Object y) {
                // UI thread, do what you need e.g. renders the list
                mAdapter.setList(y);
            }
        });

Taking care of replacing the proper types should bring you quite close to the solution.

NAUSHAD
  • 174
  • 1
  • 15
Ivan Morgillo
  • 2,837
  • 4
  • 30
  • 46
  • this is blocking e.g. if 1 call fails, it stops there; how do I make non-blocking calls in parallel @IvanMorgillo? I don't need to combine the results, I want to handle the results independently – ericn Jun 20 '17 at 01:45
  • "Func2" not supports in rxbinding:2.0.0. What shold we you instead? – Tim Kruichkov Aug 04 '17 at 14:43
  • I believe you can use this http://reactivex.io/RxJava/2.x/javadoc/io/reactivex/Observable.html#combineLatest(io.reactivex.functions.Function,%20int,%20io.reactivex.ObservableSource...) RxJava2. – Ivan Morgillo Aug 12 '17 at 15:30
2

The question is : how would you combine results ?

Building a new result from List and List ? Combine A objects with B objects ?

Answer to this question help to find the right operator for your problem.

A simple example of combining results can be this :

 getObjectAList().zipWith(getObjectBList(), (aList, bList) -> // combine both list to build a new result)).subscribe()

You can combine elements of the list too with another operator (combineLatest for example)

aObs = getObjectAList().flatMap(Observable::from);

bObs = getObjectBList().flatMap(Observable::from);
Observable.combineLatest(aObs, bObs, (a,b) -> // combine a object with b object).subscribe();

For all of this examples above, requests will be done in parallel by retrofit.

dwursteisen
  • 11,435
  • 2
  • 39
  • 36
0

I'd probably do something like the following

Observable convertedObservable = getObjectAList
            .map(object_as -> convertAToX(object_as));

Observable.combineLatest(convertedObservable, getObjectBList, (listx, listb) -> {
       return listx.addAll(listb);
    }).subscribeOn(AndroidSchedulers.mainThread())
      .observeOn(AndroidSchedulers.main)
      .subscribe(r -> {
          setAdapterWith(r);
    });

Keep in mind this is using lambdas instead of anonymous classes but you should get the gist. Map is a great way of converting one object type to another (results of A to Results of X). So you can decide how convertAToX method works for you. Then you can use combineLastest on the converted A-X and B to return the list of R which updates your adapter

Ideally this is all in a ViewModel of some kind where getObjectAList and getObjectBList can me mocked on with Mock observables and you can test all the logic easily :)

Joachim
  • 2,761
  • 1
  • 15
  • 7