user3169791
user3169791

Reputation: 351

Combining API calls with RX Java

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.

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.

Upvotes: 9

Views: 18367

Answers (3)

Ivan Morgillo
Ivan Morgillo

Reputation: 3844

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.

Upvotes: 11

Joachim
Joachim

Reputation: 2771

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 :)

Upvotes: 0

dwursteisen
dwursteisen

Reputation: 11515

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.

Upvotes: 2

Related Questions