Search code examples
androidretrofitretrofit2rx-javarx-android

The app is freezing for a little bit when using Retrofit with RxJava


JSON

[
   {
      "countryName":"..."
   },
   {
      "countryName":"..."
   },
   {
      "countryName":"..."
   } //etc... to 195 countries
]

Interface

public interface RetrofitInterface {

    @GET("GetCountries.php")
    Single<List<CountryModel>> getCountries();

}

Code

new Retrofit.Builder().baseUrl(Constants.BASE_URL).addConverterFactory(GsonConverterFactory.create()).addCallAdapterFactory(RxJava3CallAdapterFactory.create()).build().create(RetrofitInterface.class).getCountries().doOnSuccess(countryModels - > {
    for (CountryModel item: countryModels) {
        Chip chip = new Chip(requireContext());
        chip.setText(item.getCountryName());
        fragmentCountriesBinding.fragmentCountriesChipGroupMain.addView(chip);
    }
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new SingleObserver < List < CountryModel >> () {
    @Override
    public void onSubscribe(@io.reactivex.rxjava3.annotations.NonNull Disposable d) {
        
    }

    @Override
    public void onSuccess(@io.reactivex.rxjava3.annotations.NonNull List < CountryModel > countryModels) {
        
    }

    @Override
    public void onError(@io.reactivex.rxjava3.annotations.NonNull Throwable e) {
        
    }
});

I'm trying to add 195 countries to the ChipGroup but the app is freezing for a little bit during adding the chips, Firstly the code inside the doOnSuccess method was in the onSuccess method but the app was freezing for a little bit, So the code has been moved to doOnSuccess method but I get this message Only the original thread that created a view hierarchy can touch its views.

I'm new with RxJava, Any solutions?


Solution

  • You've forgot to set scheduler on what it should be subscribed. By default, an Observable and the chain of operators that you apply to it will do its work, and will notify its observers, on the same thread on which its Subscribe method is called. so if you call it from the main thread it will be executed on the main thread. It's the reason why your app is freezing, because you make network request on the main thread, responsible for UI.

    To fix it just set another scheduler with subscribeOn method:

     .subscribeOn(Schedulers.io())
    

    So in your case, it should looks something like this:

    getCountries().doOnSuccess(countryModels - > {
        ...
    }).observeOn(AndroidSchedulers.mainThread())
      .subscribeOn(Schedulers.io())   // Asynchronously subscribes  to the observable on the IO scheduler.
      .subscribe(
    
        ...
    
    )
    

    Detailed documentation: https://reactivex.io/documentation/operators/subscribeon.html

    Also the article that can be helpful to understand thread handling in RxJava: https://proandroiddev.com/understanding-rxjava-subscribeon-and-observeon-744b0c6a41ea