Combining API calls with RX Java
Asked Answered
G

3

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.

Greyhound answered 10/11, 2014 at 15:4 Comment(0)
R
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.

Revenge answered 12/8, 2015 at 10:31 Comment(3)
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 independentlyPas
"Func2" not supports in rxbinding:2.0.0. What shold we you instead?Tentation
I believe you can use this reactivex.io/RxJava/2.x/javadoc/io/reactivex/… RxJava2.Revenge
F
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.

Ferrick answered 10/11, 2014 at 16:18 Comment(0)
C
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 :)

Ce answered 31/8, 2015 at 1:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.