Android Retrofit Design Patterns

I am using Retrofit to interact with my REST API, and was wondering whether anybody has any design suggestions.

My app has the following packages:

  1. models
  2. services
  3. activities
  4. fragments

The services package contains the interfaces for Retrofit. For example:

public interface FooService {
    @FormUrlEncoded
    @POST("foo/do")
    @Headers("Content-Type: application/x-www-form-urlencoded; charset=UTF-8")
    Call<FooBar> do();
}

Models contains...well, the different models. For example, FooBar. So far so good - just as per Retrofit documentation.

I have created an API class, that handles the Retrofit build logic (Retrofit retrofit = new Retrofit.Builder() etc), and exposes a static field: retrofit.In my activities I then can perform my requests as follows:

FooService service = API.retrofit.create(FooService.class);
Call<FooBar> call = service.do();

try {
    retrofit2.Response response = call.execute();
    // ...do stuff...
} catch(IOException) {}

And herewith comes my question: Would it be better to abstract the above further? So that I would not need to repeat the above everywhere? For example, something like:

MyOtherFooService service = new  MyOtherFooService();
FooBar fooBar = service.do();

Any thoughts? Recommendations?


I usually use singleton pattern with following structure :

first define ServiceHelper like following :

public class ServiceHelper {

private static final String ENDPOINT = "http://test.com";

private static OkHttpClient httpClient = new OkHttpClient();
private static ServiceHelper instance = new ServiceHelper();
private IPlusService service;


private ServiceHelper() {

    Retrofit retrofit = createAdapter().build();
    service = retrofit.create(IPlusService.class);
}

public static ServiceHelper getInstance() {
    return instance;
}

private Retrofit.Builder createAdapter() {

    httpClient.setReadTimeout(60, TimeUnit.SECONDS);
    httpClient.setConnectTimeout(60, TimeUnit.SECONDS);
    HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
    interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
    httpClient.interceptors().add(interceptor);

    return new Retrofit.Builder()
            .baseUrl(ENDPOINT)
            .client(httpClient)
            .addConverterFactory(GsonConverterFactory.create());
}

public Call<List<CategoryModel>> getAllCategory() {
    return service.getAllCategory();
}

Then put all of your services in IService (in my case it's IPlusService)

    public interface IPlusService {
    //@Headers( "Content-Type: application/json" ) in Post method may use this
    @GET("/api/category")
    Call<List<CategoryModel>> getAllCategory();
}

Then call your singleton like below in your activity/fragment :

ServiceHelper.getInstance().getAllCategory().enqueue(new Callback<List<CategoryModel>>() {
        @Override
        public void onResponse(Response<List<CategoryModel>> response, Retrofit retrofit) {
            processResponse(response);
        }

        @Override
        public void onFailure(Throwable t) {
            processResponse(null);
        }
    });

I would say don't do it. Especialy because most calls will need to use the async .enqueue and treat the error responses differently.

You could make your own abstract Retrofit Callback class and abstract the 'custom' callbacks from that so that you save yourself code duplication.

But generally I would like to see the app logic treating the response in the same place where I make the request.

Don't fall in the trap of overthinking it, or applying some abused pattern that doesn't really fit into Android.

And if your really need to pass that response along from your activity/fragment just use RxJava or even LocalBroadcast. Also try to read the Retrofit book.