How to automatically show Progress Bar on each retrofit API call?
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.
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.
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.
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
});