Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to automatically show Progress Bar on each retrofit API call?

How to achieve showing a progress bar on each Retrofit 2.0 API call without having to make a progress bar in each activity, showing it and dismissing. Progress bar should show whenever an API is hit and it should dismiss when we get a response on onResponse or onFailure is called.

I tried this :

ProgressDialog mProgressDialog = new ProgressDialog(this);
mProgressDialog.setIndeterminate(true);
mProgressDialog.setMessage("Loading...");
mProgressDialog.show();
retrofitService.login(new SignInRequest(email, password),
                new Callback<SignInResponse>() {
         @Override
         public void onResponse(Call<SignInResponse> call, Response<SignInResponse> response) {

              if (mProgressDialog.isShowing())
                  mProgressDialog.dismiss();
          }

         @Override
         public void onFailure(Call<SignInResponse> call, Throwable t) {
              if (mProgressDialog.isShowing())
                  mProgressDialog.dismiss();
          }
 });

But this code will have to copy pasted everywhere whenever I make an API call. I don;t want duplicate code.

like image 984
Shubham A. Avatar asked Jun 03 '16 18:06

Shubham A.


4 Answers

Shameless Promotion

I've created RxLoading library for that, it can do this and much more,

you can just do something like this:

networkCall().compose(RxLoading.<>create(loadingLayout)).subscribe(...);

it consists out of 2 classes, a custom view (loadingLayout) and RxLoading which is a transformer that glue it all together, you can choose to work with both or either of them.

If you want one progress bar to rule them all, you have several options to achieve it depending on the structure of your app:

  • one Activity multiple fragments -> just put a loadingLayout in the main screen and tell it to hide the fragment layout when loading
  • multiple activities: create a base activity which all uses and inject a loadingLayout to all of you views
  • you can also make a special dialog or activity for the progress bar and use an interface for RxLoading to show and hide it.

RxLoading also supports empty and error states (with built-in retry mechanism, so make sure to check this options as well)

you can find out more on the GitHub page.

like image 122
ndori Avatar answered Sep 28 '22 09:09

ndori


A base class for your callbacks can be handy.

class BaseCallBack implements CallBacks<T>{
  @Override
     public void onResponse(Call<T> call, Response<T> response) {

          if (mProgressDialog.isShowing())
              mProgressDialog.dismiss();
      }

     @Override
     public void onFailure(Call<SignInResponse> call, Throwable t) {
          if (mProgressDialog.isShowing())
              mProgressDialog.dismiss();
      }
}

When you send a request:

retrofitService.login(new SignInRequest(email, password), new MyCallback<SignInResponse>() {
     @Override
     public void onResponse(Call<SignInResponse> call, Response<SignInResponse> response) {
          super.onResponse(call, response);
          //do more on response
      }

     @Override
     public void onFailure(Call<SignInResponse> call, Throwable t) {
          super.onFailure(call, t);
          /* Do more on failure. For example: give a reason why the
           request failed*/ 
      }
 });

Edit 2019 - using the RXjava adapter:

   getUsers()
        .subscribeOn(AndroidSchedulers.io()) //run request in the background and deliver response to the main thread aka UI thread
        .observeOn(AndroidSchedulers.mainThread())
        .doOnSubscribe(() -> showLoading())
        .doOnTerminate(() -> hideLoading())
        .subscribe(data -> {
            //request is successful
        }, error -> {
            //show error
        });
like image 12
Peter Chaula Avatar answered Oct 20 '22 21:10

Peter Chaula


As suggested by @Sourabh, I ended up using a Base activity and calling simple method during each API call. In BaseActivity,

public void showDialog() {

    if(mProgressDialog != null && !mProgressDialog.isShowing())
        mProgressDialog.show();
}

public void hideDialog() {

    if(mProgressDialog != null && mProgressDialog.isShowing())
        mProgressDialog.dismiss();
}

In your child activity, you can directly call showDialog() and hideDialog() to show and dismiss dialog.

like image 7
Shubham A. Avatar answered Oct 20 '22 23:10

Shubham A.


Based on the answers of Shubham and peter, I wrote a class like this:

class CustomCallBack<T> implements Callback<T> {

private ProgressDialog mProgressDialog;
Context context;

CustomCallBack(Context context) {
    this.context = context;
    mProgressDialog = new ProgressDialog(context);
    ((Activity) context).getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,
            WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
    mProgressDialog.setIndeterminate(true);
    mProgressDialog.setMessage("Loading...");
    mProgressDialog.setCanceledOnTouchOutside(false);
    mProgressDialog.show();

}

@Override
public void onResponse(Call<T> call, Response<T> response) {
    if (mProgressDialog.isShowing()) {
        mProgressDialog.dismiss();
        ((Activity) context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
    }

}

@Override
public void onFailure(Call<T> call, Throwable t) {
    if (mProgressDialog.isShowing()) {
        mProgressDialog.dismiss();
        ((Activity) context).getWindow().clearFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
    }

}
}

I hope it will help you.

like image 7
Amiraslan Avatar answered Oct 20 '22 22:10

Amiraslan