user3880667
user3880667

Reputation: 19

Problem executing methods after webservice call with Retrofit2 and RxJava2 when requests are combined

I resume my problem : I want to make webservice call (three calls), perform some operation on received data and finally update UI (many textview). I use retrofit2 and rxjava2 to perform webservice calls, specially Observable.zip() to make one time call for the three webservice in order to have all the three data before performing some calculation. The webservice call works well, but I have noticed that not all the instructions in my calculation method (in onComplete)are called, only the first textView.setText() is called, all that comes after is not executed. Even when I fill the method with only Log.i, not all of the are called. Same thing happens when I put the method in onNext() No error is thrown. What have I done wrong ? This is my code :

// Webservice

@GET("url 1")
Observable<List<Data1>> getData1();

@GET("url 2")
Observable<List<Data2>> getData2();

@GET("url 3")
Observable<List<Data3>> getData3();

//MainActivity

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //getTextViews
    getData();
}

private void getData(){
    Retrofit retrofit = Retrofit.Builder()
            .baseUrl("apiURL")
            .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
            .client(httpClient.build())
            .addConverterFactory(GsonConverterFactory.create(gson))
            .build();
    WebService service = retrofit.create(WebService.class);
    Observable.zip(service.getData1(), service.getData2(), service.getData3(), new Function3<List<Data1>, List<Data2>, List<Data3>, MergedResponse>() {
        int i;
        @Override
        public MergedResponse apply(List<Data1> data1, List<Data2> data2, List<Data3> data3) throws Exception {
            return new MergedResponse(data1, data2, data3);
        }
    }).subscribe(new Observer<MergedResponse>() {
        @Override
        public void onSubscribe(Disposable d) {

        }

        @Override
        public void onNext(MergedResponse mergedResponse) {
            // dispatch my merged data
        }

        @Override
        public void onError(Throwable e) {

        }

        @Override
        public void onComplete() {
            computeReceivedData();
        }
    });
}

private void computeReceivedData(){
   // List of expressions to compute data and update the view (textview)
    ...
    textView1.setText()
    textView2.setText()
    ...
   // Only the first expression textView1.setText() here is called.If I put it at the begining of the method, it stop after executing it
}

retrofit and rxjava2 vresion

implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
implementation 'com.squareup.okhttp3:logging-interceptor:3.9.0'
implementation "com.squareup.retrofit2:adapter-rxjava2:2.9.0"
implementation 'io.reactivex.rxjava2:rxjava:2.2.2'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.legacy:legacy-support-v13:1.0.0'

Upvotes: 0

Views: 88

Answers (2)

Malay
Malay

Reputation: 71

I think, you are trying to use MainThread to update UI from background thread.

So you have to add below line in your code

.subscribeOn(Schedulers.io()) // will do operation on background thread
.observeOn(AndroidSchedulers.mainThread()) // will notify UI for changes

Ex.

Observable.zip(service.getData1(), service.getData2(), service.getData3(), new Function3<List<Data1>, List<Data2>, List<Data3>, MergedResponse>() {
        int i;

        @Override
        public MergedResponse apply(List<Data1> data1, List<Data2> data2, List<Data3> data3) throws Exception {
            return new MergedResponse(data1, data2, data3);
        }
    }).subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(new Observer<MergedResponse>() {
                @Override
                public void onSubscribe(Disposable d) {

                }

                @Override
                public void onNext(MergedResponse mergedResponse) {
                    // dispatch my merged data
                }

                @Override
                public void onError(Throwable e) {

                }

                @Override
                public void onComplete() {
                    computeReceivedData();
                }
            });

Upvotes: 2

user3880667
user3880667

Reputation: 19

Thank you @yousef, I inspected textView.setText() call and found this error :

Unable to evaluate the expression "totalJ1.setText(""value");" : Method threw 'android.view.ViewRootImpl$CalledFromWrongThreadException' exception.

To solved the problem I forced the call to execute in mainThread inside onComplete():

MainActivity.this.runOnUiThread(new Runnable() {
      @Override
      public void run() {
          computeReceivedData();
      }
});

and everything works well.

Upvotes: 0

Related Questions