I understand retrofit automatically retries on failures, but I want to check for a specific error. If the error is due to a certain HTTP code, I need to retry that request after modifying it.
This can be easily done using synchronous calls, but I am making an asynchronous call (by passing callbacks). When I get the error in the callback, I want to retry the request - but all I have is the RetrofitError object (and I have lost the request body).
I have multiple requests going on from the same activity (concurrently) and so I am avoiding saving all requests and nullifying them on success.
Is there a better way to achieve this requirement ?
If you are using OkHttp as your HttpClient
and have updated to Retrofit
>= 1.9.0
then you can use the new Interceptor. Specifically, an Application Interceptor will let you retry and make multiple calls
.
You can see example pseudocode I posted on a similar question for handling expired tokens.
Also note, Retrofit 2.0
will have Interceptors
according to this GitHub ticket. That will remove the dependence on OkHttp
, though I still recommend using it.
Here's what you could try. First the network request method:
void getDataFromServer(final int dataId) {
...
dataService.getDataFromServer(dataId, new Callback<ResultData>() {
@Override
public void success(final ResultData data, final Response response) {
retries.set(0);
...
}
@Override
public void failure(RetrofitError error) {
if (RetrofitErrorHandler.retry(activity, progressDialog, error, retries, activity.getString(R.string.error_getting_data))) {
getDataFromServer(dataId);// retry this method
} else {
// let user know we counldn't get data
...
}
}
});
}
Here you could check if the request should be retried and return true if we should retry and false if we shouldn't.
The first half of retry checks if the status code of the error (see r.getStatus()
) equals which ever status code is of interest to you (see STATUS_CODE_RETRY
) which could be any server status code (e.g. 401, 404. etc.).
The second half of retry first checks to see if it was a network error (see error.isNetworkError()
) and if it is then it increments the retry counter and returns true which means that the network request will be retried. If the error is a network error (see error.isNetworkError()
) and the retry counter is greater than your desired max number of retries (see NUM_RETRIES
) then it returns false so that the request doesn't get triggered again. The next portion is the no connection check, where a network error has occurred but it's not a timeout so it must be an issue with the connection. This check returns false, as the network request should not be retried and the user should be notified of the connection issues. The final check is the non network error check, which indicates that an error has occurred that isn't a result of a network error. Once again, false is returned so the request isn't retried and the user is notified.
public static boolean retry(Activity act, RetrofitError error, AtomicInteger retries, String uploadErrorMsg){
// this is the first half of the retry check
Response r = error.getResponse();
if (r != null && r.getStatus() == STATUS_CODE_RETRY){
Log.v(TAG, "STATUS_CODE_RETRY!");
...
return true;
}
// this is the second half of the retry check
if (error.isNetworkError()) {
if (error.getCause() instanceof SocketTimeoutException) {//connection timeout check
if(retries.incrementAndGet() < NUM_RETRIES){ // retry if you can
return true;
} else { // if you can't retry anymore
retries.set(0);
Log.i(TAG, act.getClass().getSimpleName() + " has no more retries " + act.getString(R.string.timeout_msg));
return false;
}
} else {//no connection check
retries.set(0);
Log.i(TAG, act.getClass().getSimpleName() + " " + act.getString(R.string.timeout_msg)+ " " + uploadErrorMsg);
return false;
}
} else { //non network error check
retries.set(0);
Log.i(TAG, act.getClass().getSimpleName() + " " + act.getString(R.string.err_msg)+ " " + uploadErrorMsg);
return false;
}
}
Hope this helped.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With