Retrofit call contains error Required retrofit2.Call, found void - java

Hello I recently started retrofit While implementing the code im getting this error
Incompatible types.
Required: retrofit2.Call <java.util.List<com.my.package.Youtube.YoutubePost>>
Found: void
I was trying to get YouTube channel playlist using Youtube v3 API
This is my code for the same
YoutubeActivity
Retrofit retrofit = new Retrofit.Builder()
.addConverterFactory(ScalarsConverterFactory.create())
.baseUrl(AppConstant.API_YT_BASE)
.addConverterFactory(GsonConverterFactory.create())
.build();
YoutubeApiInterface youtubeApiInterface = retrofit.create(YoutubeApiInterface.class);
Call<List<YoutubePost>> call = youtubeApiInterface.getPlayList().enqueue(new Callback<List<YoutubePost>>() {
#Override
public void onResponse(Call<List<YoutubePost>> call, Response<List<YoutubePost>> response) {
if (response.isSuccessful()) {
} else {
}
}
#Override
public void onFailure(Call<List<YoutubePost>> call, Throwable t) {
t.printStackTrace();
}
});
YoutubePost
public class YoutubePost implements Parcelable {
#SerializedName("items")
private List<YoutubeItems> ytItems = new ArrayList<>();
private String nextPageToken;
public List<YoutubeItems> getYtItems() {
return ytItems;
}
public String getNextPageToken() {
return nextPageToken;
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeList(ytItems);
dest.writeString(nextPageToken);
}
protected YoutubePost(Parcel in) {
ytItems = in.readParcelable(YoutubeItems.class.getClassLoader());
nextPageToken = in.readString();
}
public static final Creator<YoutubePost> CREATOR = new Creator<YoutubePost>() {
#Override
public YoutubePost createFromParcel(Parcel source) {
return new YoutubePost(source);
}
#Override
public YoutubePost[] newArray(int size) {
return new YoutubePost[size];
}
};
}
Screenshot of error message attached below

I suggest you, to modify the getPlayList method a little bit, to return with a Call, then break the lines.
Without your YoutubeApiInterface this is all I got.
Call<List<YoutubePost>> call = youtubeApiInterface.getPlayList();
call.enqueue(new Callback<List<YoutubePost>>() {
#Override
public void onResponse(Call<List<YoutubePost>> call, Response<List<YoutubePost>> response) {
if (response.isSuccessful()) {
} else {
}
}.
#Override
public void onFailure(Call<List<YoutubePost>> call, Throwable t) {
t.printStackTrace();
}
});
By this you won't have a type problem, because the call itself will be modified, during the enqueue.

Related

How to solve E/error: End of input at line 1 column 1 path $ in android studio

When I try to call rest API in the android studio I get an error that:
E/error: End of input at line 1 column 1 path $
I use firebase for the database and retrofit2 library.
But when I call the values a go to the firebase database and call the onFailure in call.enqueue() method.
public class APis {
public static final String URL = "http://192.168.178.43:8081/api/";
public static userService setuser() {
return client.getClient(URL).create(userService.class);
}
}
public interface userService {
#Headers("Content-Type: application/json")
#POST("signup")
Call<userlog> adduser(#Body userlog userlog);
}
public class userlog {
#SerializedName("email")
#Expose
private String emial_;
#SerializedName("password")
#Expose
private String password_;
#SerializedName("name")
#Expose
private String name_;
public userlog() {
}
public userlog(String emial_, String password, String name_) {
this.emial_ = emial_;
this.password_ = password;
this.name_ = name_;
}
public String getEmial_() {
return emial_;
}
public void setEmial_(String emial_) {
this.emial_ = emial_;
}
public String getPassword_() {
return password_;
}
public void setPassword_(String password_) {
this.password_ = password_;
}
public String getName_() {
return name_;
}
public void setName_(String name_) {
this.name_ = name_;
}
}
public void setPassword_(String password_) {
this.password_ = password_;
}
}
private void adduser_(userlog userll) {
service = APis.setuser();
Call<userlog> call = service.adduser(userll);
call.enqueue(new Callback<userlog>() {
#Override
public void onResponse(Call<userlog> call, Response<userlog> response) {
if (response.isSuccessful()) {
Toast.makeText(getApplicationContext(), "Success", Toast.LENGTH_SHORT).show();
/* userdetails.setUserid(firebaseAuth.getUid());
userdetails.setEmail_(emailId.getText().toString());
startActivity(new Intent(SignupActivity.this, MainnewActivity.class));*/
}
}
#Override
public void onFailure(Call<userlog> call, Throwable t) {
Log.e("error", t.getMessage());
Toast.makeText(getApplicationContext(), "not Successdd", Toast.LENGTH_SHORT).show();
}
});
}
when I call "adduser_(userll)" method, I get a notification that "not Successdd".
The problem related to retrofit, i think the problem because the response of the call come as null or empty
you can create NullConverterFactory.class :
public class NullConverterFactory extends Converter.Factory {
#Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
return new Converter<ResponseBody, Object>() {
#Override
public Object convert(ResponseBody body) throws IOException {
if (body.contentLength() == 0) return null;
return delegate.convert(body);
}
};
}
}
and add to the create of the retrofit
baseUrl(Config.URL+"/")
.client(okHttpClient)
// -----add here-------
.addConverterFactory(new NullConverterFactory())
//---------------------
.addConverterFactory(GsonConverterFactory.create())
.build()

How to do retrofti calls with OOP?

Today i was working on my homework, which it was making simple apps with retrofit calls and learning new things for code improvement, and somehow i saw there are so many ways to write less code and do better with OOP. So to improve my code experiment I'm trying to do my retrofit calls with OOP. So this is my issue right now:
Consider a simple retrofit call with CompositeDisposable( I'm developing my simples with MVP ) :
mView.showProgress(1);
RequestRemainingProductsRequest requestRemainingProductsRequest = new RequestRemainingProductsRequest();
requestRemainingProductsRequest.distributorId = distributorId;
requestRemainingProductsRequest.requestCode = requestCode;
requestRemainingProductsRequest.requestType = 1;
NetworkCalls.getObservableList();
compositeDisposable.add(getApi().requestRemainingProducts(requestRemainingProductsRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<Products>>() {
#Override
public void accept(List<Products> products) throws Throwable {
mView.hideProgress(1);
mView.getRemainingProducts(products);
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
mView.hideProgress(1);
mView.showLog(throwable.getMessage().toString());
}
}));
And, Another retrofit call without CompositeDisposable :
ProductSellerRequest productSellerRequest = new ProductSellerRequest();
productSellerRequest.centralId = centralsList.get(i).requestCentralId;
productSellerRequest.requestType = 0;
productSellerRequest.productId = Constant.currentProduct.productId;
getApi().checkProductExistInRequest(productSellerRequest)
.enqueue(new Callback<ProductSellerCallback>() {
#Override
public void onResponse(Call<ProductSellerCallback> call, Response<ProductSellerCallback> response) {
hideProgress(myViewHolder);
showAddDialog(myViewHolder, v, response, i);
}
#Override
public void onFailure(Call<ProductSellerCallback> call, Throwable t) {
hideProgress(myViewHolder);
}
});
So let's say I created a java class with NetworkCalls.java, and created 2 voids like this:
public static void getObservableList()
{
}
public static void getWithoutObservableList()
{
}
How to handle my response to return to my Presenter/Activity?
This is how i using StringBuilder and returning my String, but I'm trying do similiar way to make repository for my Network Calls, then learn all all i should know about Repository Pattern.
public static String TotalPriceStringBuilder(int Price){
String DecimalPrice = String.format("%,d", Price);
String FinalString = new StringBuilder("Price : ").append(DecimalPrice).append(" $").toString();
return String.valueOf(FinalString);
}
This is what I've tried, but i still don't know how to fix it or make it work, what to return, and how to return and etc... :
private static ApiClient mApi;
private List<Products> receivedProducts;
private int hideProgress;
private boolean status;
private String message;
public void getObservableList(RequestRemainingProductsRequest requestRemainingProductsRequest, CompositeDisposable compositeDisposable)
{
compositeDisposable.add(getApi().requestRemainingProducts(requestRemainingProductsRequest)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer<List<Products>>() {
#Override
public void accept(List<Products> products) throws Throwable {
hideProgress = 1;
receivedProducts = products;
status = TRUE;
}
}, new Consumer<Throwable>() {
#Override
public void accept(Throwable throwable) throws Exception {
hideProgress = 1;
status = FALSE;
message = throwable.getMessage().toString();
}
}));
if (status == TRUE) {
return hideProgress, receivedProducts, status;
} else {
return hideProgress, message, status;
}
}
public ApiClient getApi() {
if (mApi == null) {
mApi = ApiService.getClient().create(ApiClient.class);
}
return mApi;
}
If i use static method I'll get bunch of errors like can't be refrenced from a static context or etc...

How to return something from a callback function to parent function

This is what I got to do
UploadCompleteListener is a custom interface that acts as a callback.
#Overrider
public Result doWork() {
mUpLoadDataService.uploadInspectionData(new UpLoadDataService.UploadCompleteListener() {
#Override
public void uploadComplete() {
return Result.success(); //this is what I want to do
}
#Override
public void uploadFailed(String reason) {
return Result.failure(); //this is what I want to do
}
});
return null;
}
Is it Possible?
If possible in any way please response soon. I can provide more details if you need it.
** This is what worked for me **
#NonNull
#Override
public Result doWork() {
final Result[] result = new Result[1];
mUpLoadDataService.uploadInspectionData(new UpLoadDataService.UploadCompleteListener() {
#Override
public void uploadComplete() {
result[0] = Result.success(); //this is what I want to do
}
#Override
public void uploadFailed(String reason) {
result[0] = Result.failure(); //this is what I want to do
}
});
return result[0];
}
public Result doWork(UpLoadDataService.UploadCompleteListener uploadListener) {
mUpLoadDataService.uploadInspectionData(uploadListener);
return null;
}
now pass the implementation from parent function. Lets say your parent function is named foobar
void foobar() {
someObject.doWork(new UpLoadDataService.UploadCompleteListener() {
#Override
public void uploadComplete() {
//write your logic here
return Result.success();
}
#Override
public void uploadFailed(String reason) {
//write your logic here
return Result.failure();
}
});
}
You have to realize that you are trying to get synchronously a result from an asynchronous call. This call is asynchronous for a reason, so the short answer is no, you can't.
Instead of returning a Result, you could return, for instance, a Future, which models the asynchronicity of the operation.
For android take a look at CallbackToFutureAdapter
https://developer.android.com/reference/kotlin/androidx/concurrent/futures/CallbackToFutureAdapter
https://developer.android.com/reference/java/util/concurrent/Future
You could use EventBus to notify Subscribed methods in every place you want like so:
public class MessageEvent {
public final String message;
public MessageEvent(String message) {
this.message = message;
}
}
public void doWork() {
mUpLoadDataService.uploadInspectionData(new UpLoadDataService.UploadCompleteListener() {
#Override
public void uploadComplete() {
EventBus.getDefault().post(new MessageEvent("success"));
}
#Override
public void uploadFailed(String reason) {
EventBus.getDefault().post(new MessageEvent("failed"));
}
});
}
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
Toast.makeText(getActivity(), event.message, Toast.LENGTH_SHORT).show();
}
See this implementation guide.
You can get the callback of your task using the following way
doWork(paremter, new ServiceListener<String>() { //paremter if any
#Override
public void success(String obj) {
//get the response if success
}
#Override
public void fail(ServiceError error) {
//get the error response
}
});
do the work and send the call response from where it called
private void doWork(String param , ServiceListener<String> serviceListener) {
mUpLoadDataService.uploadInspectionData(new UpLoadDataService.UploadCompleteListener() {
#Override
public void uploadComplete() {
serviceListener.success("success");
}
#Override
public void uploadFailed(String reason) {
serviceListener.fail(new ServiceError("Can not Upload"));
}
});
}
ServiceListener interface will be defined as follow
public interface ServiceListener<T> {
void success(T obj);
void fail(ServiceError error);
}
public class ServiceError {
public Throwable errorObject;
public String message;
public ServiceError(){
message = "";
}
public ServiceError(String message){
this.message = message;
}
public ServiceError(String message, Throwable errorObject){
this.message = message;
this.errorObject = errorObject;
}
public Object getErrorObject() {
return errorObject;
}
public void setErrorObject(Throwable errorObject) {
this.errorObject = errorObject;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

Retrofit 2 - response body returns null (response code is 200)

I have a json file like this:
{
"response":{
"ApplicationList":[
{
"Id":1,
"Name":"SomeApp"
}
],
"Token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYW1laWQiOiIyMyIsIm5iZiI6MTUxNDIwMDkyMiwiZXhwIjoxNTQ1NzM2OTIyLCJpYXQiOjE1MTQyMDA5MjJ9.9nyaBfbxPlg8T8WkbBBi34II9NZMtyRpeEJ1s1XCJlo"
},
"errorMessageId":0,
"errorMessage":null
}
I'm using Retrofit library and I have checked the response with Interceptor level BODY which shows that response is good (like above).
I have created models using http://www.jsonschema2pojo.org/ but for some reason, parsing to java model isn't going as supposed to. I'm getting all null values for attributes in model.
Here are my model classes:
public class SignInUsersResponse implements Parcelable{
public Response response;
public Integer errorMessageId;
public String errorMessage;
#Override
public String toString() {
return "SignInUsersResponse{" +
"response=" + response +
", errorMessageId=" + errorMessageId +
", errorMessage='" + errorMessage + '\'' +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(this.response, flags);
dest.writeValue(this.errorMessageId);
dest.writeString(this.errorMessage);
}
public SignInUsersResponse() {
}
protected SignInUsersResponse(Parcel in) {
this.response = in.readParcelable(Response.class.getClassLoader());
this.errorMessageId = (Integer) in.readValue(Integer.class.getClassLoader());
this.errorMessage = in.readString();
}
public static final Creator<SignInUsersResponse> CREATOR = new Creator<SignInUsersResponse>() {
#Override
public SignInUsersResponse createFromParcel(Parcel source) {
return new SignInUsersResponse(source);
}
#Override
public SignInUsersResponse[] newArray(int size) {
return new SignInUsersResponse[size];
}
};
}
public class Response implements Parcelable{
public List<ApplicationList> applicationList = null;
public String token;
#Override
public String toString() {
return "Response{" +
"applicationList=" + applicationList +
", token='" + token + '\'' +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeTypedList(this.applicationList);
dest.writeString(this.token);
}
public Response() {
}
protected Response(Parcel in) {
this.applicationList = in.createTypedArrayList(ApplicationList.CREATOR);
this.token = in.readString();
}
public static final Creator<Response> CREATOR = new Creator<Response>() {
#Override
public Response createFromParcel(Parcel source) {
return new Response(source);
}
#Override
public Response[] newArray(int size) {
return new Response[size];
}
};
}
public class ApplicationList implements Parcelable{
public Integer id;
public String name;
#Override
public String toString() {
return "ApplicationList{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
#Override
public int describeContents() {
return 0;
}
#Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeValue(this.id);
dest.writeString(this.name);
}
public ApplicationList() {
}
protected ApplicationList(Parcel in) {
this.id = (Integer) in.readValue(Integer.class.getClassLoader());
this.name = in.readString();
}
public static final Creator<ApplicationList> CREATOR = new Creator<ApplicationList>() {
#Override
public ApplicationList createFromParcel(Parcel source) {
return new ApplicationList(source);
}
#Override
public ApplicationList[] newArray(int size) {
return new ApplicationList[size];
}
};
}
All three are in different class files.
And this is how I call the server:
RHDRService rhdrService = ApiUtilsUser.rhdrService(Constants.RHUSER_BASE_URL);
Call<SignInUsersResponse> call = rhdrService.signInUser(signInUserPost);
call.enqueue(new Callback<SignInUsersResponse>() {
#Override
public void onResponse(Call<SignInUsersResponse> call, Response<SignInUsersResponse> response) {
Log.d("test", response.body().toString());
}
#Override
public void onFailure(Call<SignInUsersResponse> call, Throwable t) {
}
});
This is what is logged:
D/test: SignInUsersResponse{response=Response{applicationList=null, token='null'}, errorMessageId=0, errorMessage='null'}
This is how the other files which are used for Retrofit call are declared:
public class ApiUtilsUser {
public static RHDRService rhdrService(String base_url) {
return RetroFitClientUser.getClient(base_url).create(RHDRService.class);
}
}
public class RetroFitClientUser {
private static Retrofit retrofit = null;
public static Retrofit getClient(String baseUrl) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
// set your desired log level
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
// add your other interceptors …
// add logging as last interceptor
httpClient.addInterceptor(logging); // <-- this is the important line!
retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.client(httpClient.build()) // Ako nećemo logovanje onda ova linija ne treba
.build();
return retrofit;
}
}
public interface RHDRService {
#Headers( "Content-Type: application/json" )
#POST("api/user/signin")
Call<SignInUsersResponse> signInUser (#Body SignInUserPost signInUserPost);
}
Your JSON and POJO differ.
By default, Gson uses FieldNamingPolicy.IDENTITY as field naming policy. This field naming policy is used to map the JSON to your POJO and it is case sensitive.
You can either use a different field naming policy or use #SerializedName to indicate that the field should be deserialized with the given name.
class MyPojo {
#SerializedName("ApplicationList")
List<Application> applicationList;
}

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 */);
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.
I've made custom implementation of the Callback interface, you can pretty much use it in place of original callback. If call is successful, the onResponse() method is called. If after retrying for set amount of repetitions call fails, onFailedAfterRetry() is called.
public abstract class BackoffCallback<T> implements Callback<T> {
private static final int RETRY_COUNT = 3;
/**
* Base retry delay for exponential backoff, in Milliseconds
*/
private static final double RETRY_DELAY = 300;
private int retryCount = 0;
#Override
public void onFailure(final Call<T> call, Throwable t) {
retryCount++;
if (retryCount <= RETRY_COUNT) {
int expDelay = (int) (RETRY_DELAY * Math.pow(2, Math.max(0, retryCount - 1)));
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
retry(call);
}
}, expDelay);
} else {
onFailedAfterRetry(t);
}
}
private void retry(Call<T> call) {
call.clone().enqueue(this);
}
public abstract void onFailedAfterRetry(Throwable t);
}
https://gist.github.com/milechainsaw/811c1b583706da60417ed10d35d2808f
ashkan-sarlak answer work great and i'm just try to make it up to date.
From retrofit 2.1
onFailure(Throwable t)
Change to
onFailure(Call<T> call, Throwable t)
So this make it so easy now.just create CallbackWithRetry.java like this
public abstract class CallbackWithRetry<T> implements Callback<T> {
private static final int TOTAL_RETRIES = 3;
private static final String TAG = CallbackWithRetry.class.getSimpleName();
private int retryCount = 0;
#Override
public void onFailure(Call<T> call, Throwable t) {
Log.e(TAG, t.getLocalizedMessage());
if (retryCount++ < TOTAL_RETRIES) {
Log.v(TAG, "Retrying... (" + retryCount + " out of " + TOTAL_RETRIES + ")");
retry(call);
}
}
private void retry(Call<T> call) {
call.clone().enqueue(this);
}
}
That's all! you can simply use it like this
call.enqueue(new CallbackWithRetry<someResponseClass>() {
#Override
public void onResponse(#NonNull Call<someResponseClass> call, #NonNull retrofit2.Response<someResponseClass> response) {
//do what you want
}
#Override
public void onFailure(#NonNull Call<someResponseClass> call, #NonNull Throwable t) {
super.onFailure(call,t);
//do some thing to show ui you trying
//or don't show! its optional
}
});
Go with RxJava Observable and call retry()
Doc: https://github.com/ReactiveX/RxJava/wiki/Error-Handling-Operators
I did something quite similar to Ashkan Sarlak, but since Retrofit 2.1 passes the Call<T> into the onFailure method, you can simplify to one CallbackWithRetry<T> abstract class. See:
public abstract class CallbackWithRetry<T> implements Callback<T> {
private static final String TAG = "CallbackWithRetry";
private int retryCount = 0;
private final Logger logger;
private final String requestName;
private final int retryAttempts;
protected CallbackWithRetry(#NonNull Logger logger, #NonNull String requestName, int retryAttempts) {
this.logger = logger;
this.requestName = requestName;
this.retryAttempts = retryAttempts;
}
#Override
public void onFailure(Call<T> call, Throwable t) {
if (retryCount < retryAttempts) {
logger.e(TAG, "Retrying ", requestName, "... (", retryCount, " out of ", retryAttempts, ")");
retry(call);
retryCount += 1;
} else {
logger.e(TAG, "Failed request ", requestName, " after ", retryAttempts, " attempts");
}
}
private void retry(Call<T> call) {
call.clone().enqueue(this);
}
}
With Retrofit 2.5
Now it's possible to make async sync calls through java.util.concurrent.CompletableFuture, the code waits for it's completion wich is very nice.
Here's a gist with a working solution.
Another solution for this problem if retry is optional :
public class CustomCallback<T> implements Callback<T> {
#NonNull
Callback<T> callback;
private int retryCount = 0;
private int maxRetry = 0;
#EverythingIsNonNull
public CustomCallback(Callback<T> callback) {
this.callback = callback;
}
public CustomCallback<T> retryOnFailure(int nbRetry) {
maxRetry = nbRetry;
return this;
}
#EverythingIsNonNull
#Override
public void onResponse(Call<T> call, Response<T> response) {
callback.onResponse(call, response);
}
#EverythingIsNonNull
#Override
public void onFailure(Call<T> call, Throwable t) {
if (maxRetry > retryCount) {
retryCount++;
call.clone().enqueue(this);
return;
}
callback.onFailure(call, t);
}
}
This way, you can choose if you want retry or not :
//With retry
myAPI.makeCall().enqueue(new CustomCallback<>(myCallback).retryOnFailure(3));
//Without
myAPI.makeCall().enqueue(new CustomCallback<>(myCallback));
I think for android we no need to go for retrofit for this.We can make use of Workmanager (which predefine android api).
We can use "ListenableWorker.Result.SUCCESS","ListenableWorker.Result.RETRY" ,etc and achieve the above goals.

Categories

Resources