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:
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?
Retrofit uses about 12 design patterns : 1- Builder Pattern: to separate the construction of a complex object from its representation.
The singleton pattern ensures that only one object of a particular class is ever created. All further references to objects of the singleton class refer to the same underlying instance. There are very few applications, do not overuse this pattern. It's very easy to accomplish in Kotlin but not in java.
Retrofit is type-safe REST client for Android and Java which aims to make it easier to consume RESTful web services. We'll not go into the details of Retrofit 1. x versions and jump onto Retrofit 2 directly which has a lot of new features and a changed internal API compared to the previous versions.
A facade, in the context of software design, is an object that provides a simplified interface to a larger body (or more complex) functionalities. This is useful especially when the client just need to simply call the interface in order to perform some tasks without having to know the implementation details of it.
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.
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