How I use Retrofit using Java Generic Types:
You can use the interfaces in "BaseRetrofitHelper" to do Async Calls.
public abstract class BaseRetrofitHelper {
/** START Callback Interfaces **/
public interface IJsonObjectCallback {
void OnJsonObjectResponse(Integer requestCase, JsonObject answer);
void OnJsonObjectFailure(Integer requestCase, Throwable t);
}
public interface IResponseBodyCallback {
void OnResponseBodySuccess(Integer reqCase, ResponseBody response);
void OnResponseBodyError(Integer reqCase, Throwable t);
}
public interface IBaseResponseCallback{
void OnBaseResponseSuccess(Integer requestCase, BaseResponse answer);
void OnBaseResponseFailure(Integer requestCase, Throwable t);
}
public interface IBaseItemResponseCallback<T>{
void OnBaseItemResponseSuccess(Integer reqCase, BaseItemResponse<T> answer);
void OnBaseItemResponseError(Integer reqCase, Throwable t);
}
public interface IGetItemBaseResponseCallback<T>{
void OnGetItemBaseResponseSuccess(Integer reqCase, T answer);
void OnGetItemBaseResponseError(Integer reqCase, Throwable t);
}
public interface IBaseItemsResponseCallback<T>{
void OnBaseItemsResponseSuccess(Integer reqCase, BaseItemsResponse<T> answer);
void OnBaseItemsResponseError(Integer reqCase, Throwable t);
}
public interface IGetItemsBaseResponseCallback<T>{
void OnGetItemsBaseResponseSuccess(Integer reqCase, List<T> answer);
void OnGetItemsBaseResponseError(Integer reqCase, Throwable t);
}
/** END Callback Interfaces **/
// Logcats
protected final String LOGCAT = this.getClass().getSimpleName();
// Timeouts
public static final String CONNECT_TIMEOUT = "CONNECT_TIMEOUT";
public static final String READ_TIMEOUT = "READ_TIMEOUT";
public static final String WRITE_TIMEOUT = "WRITE_TIMEOUT";
private static Retrofit mRetrofit;
private static String mBaseUrl;
/* INIT YOUR RETROFIT INSTANCE HERE */
/* START Getter & Setter Methods */
public static String getBaseUrl() {
return mBaseUrl;
}
/* END Getter & Setter Methods */
/* START Public Methods */
public <T> T createService(Class<T> service) {
return mRetrofit.create(service);
}
/* END Public Methods */
/* START Protected Methods */
String getJsonRequest(LinkedHashMap<String, String> paramsToJson) {
Gson gson = new Gson();
return gson.toJson(paramsToJson, LinkedHashMap.class);
}
/* START Sync Request Methods */
protected <T> T executeSyncCall(ExecutorService exe, Call<T> call){
return new ResponseExecutorCallable<>(exe, call).executeSyncCall();
}
public <T> T executeSyncCall(Call<T> call){
return new ResponseExecutorCallable<>(newSingleThreadExecutor(), call).executeSyncCall();
}
public boolean getBaseResponseSuccess(Call<? extends BaseResponse> call){
return new BaseResponseExecutorCallable<>(newSingleThreadExecutor(), call).getBaseResponseSuccess();
}
String getBaseResponseMessage(Call<? extends BaseResponse> call){
return new BaseResponseExecutorCallable<>(newSingleThreadExecutor(), call).getBaseResponseMessage();
}
protected <T> List<T> getBaseResponseItems(Call<BaseItemsResponse<T>> call){
return new BaseItemsResponseExecutorCallable<T>(newSingleThreadExecutor(), call).getBaseResponseItems();
}
protected <T> T getBaseResponseItem(Call<BaseItemResponse<T>> call){
return new BaseItemResponseExecutorCallable<T>(newSingleThreadExecutor(), call).getBaseResponseItem();
}
/* END Sync Request Methods */
/* START Check Methods */
protected JsonObject checkGetJsonObject(Response<JsonObject> response){
JsonObject answer = null;
if(response != null && response.isSuccessful()){
answer = response.body();
}
return answer;
}
ResponseBody checkResponseBody(Response<ResponseBody> response){
ResponseBody answer = null;
if(response != null && response.isSuccessful()){
answer = response.body();
}
return answer;
}
protected BaseResponse checkBaseResponse(Response<BaseResponse> response){
BaseResponse answer = null;
if(response != null && response.isSuccessful()){
answer = response.body();
}
return answer;
}
protected <T> BaseItemResponse<T> checkBaseItemResponse(Response<BaseItemResponse<T>> response){
BaseItemResponse<T> answer = null;
if(response != null && response.isSuccessful()){
answer = response.body();
}
return answer;
}
protected <T> T checkGetBaseResponseItem(Response<BaseItemResponse<T>> response){
T item = null;
if(response != null && response.isSuccessful()){
BaseItemResponse<T> answer = response.body();
if(answer != null && answer.getSuccess()){
item = answer.getItem();
}
}
return item;
}
<T> BaseItemsResponse<T> checkBaseItemsResponse(Response<BaseItemsResponse<T>> response){
BaseItemsResponse<T> answer = null;
if(response != null && response.isSuccessful()){
answer = response.body();
}
return answer;
}
protected <T> List<T> checkGetBaseResponseItems(Response<BaseItemsResponse<T>> response){
List<T> items = null;
if(response != null && response.isSuccessful()){
BaseItemsResponse<T> answer = response.body();
if(answer != null && answer.getSuccess()){
items = answer.getItems();
}
}
return items;
}
/* END Check Methods *//* END Protected Methods */
/** START Private Classes **/
private class ResponseExecutorCallable<T> implements Callable<T>{
private ExecutorService mExecutorService;
private Call<T> mCall;
ResponseExecutorCallable(ExecutorService exe, Call<T> call){
this.mExecutorService = exe;
this.mCall = call;
}
/* START Override Callable Methods */
@Override
public T call() {
T ret = null;
try {
Response<T> response = mCall.execute();
if (response != null && response.isSuccessful()) {
ret = response.body();
}
} catch(IOException ioE){
onException(ioE);
}
return ret;
}
/* END Override Callable Methods */
/* START Public Methods */
T executeSyncCall(){
T ret = null;
try{
ret = mExecutorService.submit(this).get();
} catch(ExecutionException | InterruptedException eiE){
onException(eiE);
}
return ret;
}
/* END Public Methods */
}
private class BaseResponseExecutorCallable<T extends BaseResponse> extends ResponseExecutorCallable<T> {
BaseResponseExecutorCallable(ExecutorService exe, Call<T> call){
super(exe, call);
}
/* START Public Methods */
boolean getBaseResponseSuccess(){
boolean ret = false;
T res = super.executeSyncCall();
if(res != null){
ret = res.getSuccess();
}
return ret;
}
String getBaseResponseMessage(){
String ret = null;
T res = super.executeSyncCall();
if(res != null && res.getSuccess()){
ret = res.getMsg();
}
return ret;
}
/* END Public Methods */
}
private class BaseItemResponseExecutorCallable<T> extends BaseResponseExecutorCallable<BaseItemResponse<T>>{
BaseItemResponseExecutorCallable(ExecutorService exe, Call<BaseItemResponse<T>> call){
super(exe, call);
}
/* START Public Methods */
<T> T getBaseResponseItem(){
T ret = null;
BaseItemResponse<T> res = (BaseItemResponse<T>) super.executeSyncCall();
if(res != null && res.getSuccess()){
ret = res.getItem();
}
return ret;
}
/* END Public Methods */
}
private class BaseItemsResponseExecutorCallable<T> extends BaseResponseExecutorCallable<BaseItemsResponse<T>>{
BaseItemsResponseExecutorCallable(ExecutorService exe, Call<BaseItemsResponse<T>> call){
super(exe, call);
}
/* START Public Methods */
<T> List<T> getBaseResponseItems(){
List ret = null;
BaseItemsResponse<T> res = (BaseItemsResponse<T>) super.executeSyncCall();
if(res != null && res.getSuccess()){
ret = res.getItems();
}
return ret;
}
/* END Public Methods */
}
/** END Private Classes **/
}
My Responses:
public class BaseResponse {
@SerializedName("success")
protected Boolean mSuccess;
@SerializedName("msg")
protected String mMsg;
@SerializedName("errors")
protected String mErrors;
/* START Getter & Setter Methods */
public Boolean getSuccess() {
return mSuccess;
}
public void setSuccess(Boolean success) {
this.mSuccess = success;
}
public String getMsg() {
return mMsg;
}
public void setMsg(String msg) {
this.mMsg = msg;
}
public String getErrors() {
return mErrors;
}
public void setErrors(String errors) {
this.mErrors = errors;
}
/* END Getter & Setter Methods */
@Override
public String toString() {
return "BaseResponse{" +
"mSuccess=" + mSuccess +
", mMsg='" + mMsg + '\'' +
", mErrors='" + mErrors + '\'' +
'}';
}
}
public class BaseItemResponse<T> extends BaseResponse {
@SerializedName(value = "item", alternate = {"..."})
private T mItem;
/* START Getter & Setter Methods */
public T getItem() {
return mItem;
}
public void setItem(T mItem) {
this.mItem = mItem;
}
/* END Getter & Setter Methods */
@Override
public String toString() {
return "BaseItemResponse{" +
"mItem=" + mItem +
", mSuccess=" + mSuccess +
", mMsg='" + mMsg + '\'' +
", mErrors='" + mErrors + '\'' +
'}';
}
}
public class BaseItemsResponse<T> extends BaseResponse {
@SerializedName(value = "items", alternate = {"...."})
private List<T> mItems;
/* START Getter & Setter Methods */
public List<T> getItems() {
return mItems;
}
public void setItems(List<T> items) {
this.mItems = items;
}
/* END Getter & Setter Methods */
@Override
public String toString() {
return "BaseItemsResponse{" +
"mItems=" + mItems +
", mSuccess=" + mSuccess +
", mMsg='" + mMsg + '\'' +
", mErrors='" + mErrors + '\'' +
'}';
}
}
Usage for Sync Calls:
Create a "RetrofitHelper" class which extends "BaseRetrofitHelper".
In this class make your methods. You can do a Sync call in another thread which will wait until it finished the Networking Operation just doing this:
public List<YOURCLASS> requestSyncListYOURCLASS(String url, String token, HashMap<String, Object> data){
YourAPI api = createService(YourAPI.class);
String params = JsonUtils.buildB64EncodedParams(token, data);
Call<BaseItemsResponse<YOURCLASS>> call = api.getListYOURCLASS(url, params);
return super.getBaseResponseItems(call);
}
With this method you get a List of "YOURCLASS" elements in your activity. The networking operation is done in an another thread so you won't get the 'NetworkingOnMainThreadException' and also you don't need to set the 'Policy' to 'PermitAll' to solve the 'NetworkingOnMainThreadException'. (Change the policy to permit networking in your main thread is really a bad thing!)
Usage for Async Calls:
Personally I prefer to always use, when possible, Async Calls to do networking operation. That's why in the Interfaces you have a 'Integer requestCase' parameter: when you have to do multiple networking operations whose use all the same Callback you just need to pass an integer value as 'requestCase' (reqCase) which will identify which operation finished. In the 'Success' and 'Error' callback methods you just need to put a 'switch(requestCase)' statement to know which operation finished and returned his results.
----> When you implement the callback interface in your activity you can specify the result's class you expect as his Type Parameter, if you will always get back the same class of objects when the networking operations return.
Otherwise if you have multiple kind of object classes returned using the same callback methods you should not give a Type Parameter to the Interface when you implements it.
public void requestAsyncListYOURCLASS(String url, String token, HashMap<String, Object> data, final Integer reqCase,
final IGetItemsBaseResponseCallback<YOURCLASS> callback) {
String params = JsonUtils.buildB64EncodedParams(token, data);
YourAPI api = createService(YourAPI.class);
Call<BaseItemsResponse<YOURCLASS>> call = api.getListYOURCLASS(url, params);
call.enqueue(new Callback<BaseItemsResponse<YOURCLASS>>() {
@Override
public void onResponse(Call<BaseItemsResponse<YOURCLASS>> call, Response<BaseItemsResponse<YOURCLASS>> response) {
callback.OnGetItemsBaseResponseSuccess(reqCase, checkGetBaseResponseItems(response));
}
@Override
public void onFailure(Call<BaseItemsResponse<YOURCLASS>> call, Throwable t) {
callback.OnGetItemsBaseResponseError(reqCase, t);
}
});
}
Hope this is helpful for you! Thank you, Bye All :D