Rohan
Rohan

Reputation: 188

Chaining two web service calls using RxJava and Retrofit

I am using RxJava and Retrofit.My basic requirement is,i want to chain two api calls, which will get called one after one another. Response received from first api is used as input while calling second api. After reading some stuff on internet i used to flatmap to achieve this. While carrying out this operation i am showing loader.Sometimes it runs smoothly but on some occasions this loader freezes. DDMS shows log of "skipped 300 frames,Application may be doing too much work on its main thread". I suspect one of my network call is running on main thread. I am not able to figure out how to chain these two calls so that they can be smoothly called in background without hampering my main thread. Any help is greatly appreciated . Thanks in advance This is what i have tried so far

private CompositeSubscription mSubscriptions = new CompositeSubscription();

Subscription subscription = Observable.just(getAddress())
          .subscribeOn(Schedulers.newThread())
          .flatMap(address -> mPlatformApi.secondWebService(address.getLatitude(),address.getLongitude())
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(modelTwo ->
          {
            //updating My ui
          }, throwable -> {

            //Error Handling
          });

mSubscriptions.add(subscription);


private android.location.Address getAddress(){
    String addressString = "";//some Address String
    Geocoder coder = new Geocoder(getActivity());
    android.location.Address address=null;
    try {
      ArrayList<android.location.Address> addressList = (ArrayList<android.location.Address>) coder.getFromLocationName(addressString, 1);
      if(addressList !=null && addressList.size()>0) {
        address = addressList.get(0);
      } else {

      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return address;
  }

//My Retrofit call
Observable<modelTwo> secondWebService(@Path("lat") double lat,@Path("lon") double lon);

Upvotes: 4

Views: 4107

Answers (1)

david.mihola
david.mihola

Reputation: 12982

Consider this:

final android.location.Address address = getAddress();
Subscription subscription = Observable.just(address) ...

This is equivalent to your code, but should also make it clear that getAddress() is evaluated before RxJava is involved and has had any chance to intervene. In other words, when you use just, the subscribeOn can only move the emission of the Address (calling onNext(address) on your Subscriber) to another thread. However, the creation of the Address - that is, your getAddress - will already have happened on the main thread when you get to this point.

The easiest way to actually move getAddress to another thread is to use defer:

Subscription subscription = Observable.defer(new
          Func0<Observable<android.location.Address>>() {

              @Override
              public Observable<android.location.Address> call() {
                  return Observable.just(getAddress());
              }
          })
          .subscribeOn(Schedulers.newThread())
          .flatMap(address -> mPlatformApi.secondWebService(address.getLatitude(),address.getLongitude()    )
          .observeOn(AndroidSchedulers.mainThread())
          .subscribe(modelTwo ->
          {
            //updating My ui
          }, throwable -> {
            //Error Handling
          });

This way, the whole Func0 will be executed on newThread() - not only the just but also the getAddress.

Upvotes: 6

Related Questions