Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrying the request using Retrofit 2

How can I add retry functionality to the requests sent by Retrofit 2 library. Something like:

service.listItems().enqueue(new Callback<List<Item>>() {         @Override         public void onResponse(Response<List<Item>> response) {             ...         }          @Override         public void onFailure(Throwable t) {             ...         }     }).retryOnFailure(5 /* times */); 
like image 416
Ashkan Sarlak Avatar asked Sep 15 '15 07:09

Ashkan Sarlak


People also ask

Does Retrofit have retry policy?

Now , retrofit does not come with retry support by default (although it was in their spec for their 2.0 release). If you are using Rx in your android app ,you can add the Retrofit Rx adapter and use RxJava observables for retrying.

What is the difference between retrofit and OkHttp?

OkHttp is a pure HTTP/SPDY client responsible for any low-level network operations, caching, requests and responses manipulation. In contrast, Retrofit is a high-level REST abstraction build on top of OkHttp. Retrofit is strongly coupled with OkHttp and makes intensive use of it.

What is retrofit interceptor?

Retrofit is a popular, simple and flexible library to handle network requests in android development.


1 Answers

I finally did something like this, for anyone interested:

1

First I made an abstract class CallbackWithRetry

public abstract class CallbackWithRetry<T> implements Callback<T> {      private static final int TOTAL_RETRIES = 3;     private static final String TAG = CallbackWithRetry.class.getSimpleName();     private final Call<T> call;     private int retryCount = 0;      public CallbackWithRetry(Call<T> call) {         this.call = call;     }      @Override     public void onFailure(Throwable t) {         Log.e(TAG, t.getLocalizedMessage());         if (retryCount++ < TOTAL_RETRIES) {             Log.v(TAG, "Retrying... (" + retryCount + " out of " + TOTAL_RETRIES + ")");             retry();         }     }      private void retry() {         call.clone().enqueue(this);     } } 

Using this class I can do something like this:

serviceCall.enqueue(new CallbackWithRetry<List<Album>>(serviceCall) {     @Override     public void onResponse(Response<List<Album>> response) {         ...     } }); 

2

This is not completely satisfactory because I have to pass same serviceCall twice. This can confusing as one can think the second serviceCall (that goes into constructor of CallbackWithRetry) should or could be something different from first one (which we invoke enqueue method on it)

So I implemented a helper class CallUtils:

public class CallUtils {      public static <T> void enqueueWithRetry(Call<T> call, final Callback<T> callback) {         call.enqueue(new CallbackWithRetry<T>(call) {             @Override             public void onResponse(Response<T> response) {                 callback.onResponse(response);             }              @Override             public void onFailure(Throwable t) {                 super.onFailure(t);                 callback.onFailure(t);             }         });     }  } 

And I can use it like this:

CallUtils.enqueueWithRetry(serviceCall, new Callback<List<Album>>() {     @Override     public void onResponse(Response<List<Album>> response) {         ...     }      @Override     public void onFailure(Throwable t) {         // Let the underlying method do the job of retrying.     } }); 

With this I have to pass a standard Callback to enqueueWithRetry method and it makes me implement onFailure (Though in the previous method I can implement it too)

So this is how I've solved the issue. Any suggestion for a better design would be appreciated.

like image 69
Ashkan Sarlak Avatar answered Sep 22 '22 22:09

Ashkan Sarlak