I have a problem with Retrofit and duplicate checking.
I have to check every time response status code or type!
I need a wrapper for request method that checks there this duplicate works.
(duplicate works includes: showLoading(),response.code(),onFailure() handle...).
I need a GenericMethod for this:
UserService service = RetrofitInstance.getRetrofitInstance().create(UserService.class);
service.RequestVerification(token, mobileNumber).enqueue(new Callback<ClientData<User>>() {
#Override
public void onResponse(#NonNull Call<ClientData<User>> call, #NonNull Response<ClientData<User>> response) {
doAction();//Action must passed to this method.
GeneralTools.hideLoading();
}
#Override
public void onFailure(#NonNull Call<ClientData<User>> call, #NonNull Throwable t) {
GeneralTools.hideLoading();
dialogError.show();
}
});
Try below
private static class CallbackHandler<T> implements Callback<T> {
#Override
public void onResponse(Call<T> call, Response<T> response) {
int code = response.code();
if (code >= 200 && code < 300) {
onSuccess(response);
} else if (code == 401) {
// logic to refresh token or user then recall the same api
call.clone().enqueue(this);
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
}
public void onSuccess(Response<T> response) {
}
}
Then change your call like below
service.RequestVerification(token, mobileNumber).enqueue(new CallbackHandler<ClientData<User>>() {
#Override
public void onSuccess(Response<ClientData<User>> response) {
doAction();//Action must passed to this method.
GeneralTools.hideLoading();
}
#Override
public void onFailure(#NonNull Call<ClientData<User>> call, #NonNull Throwable t) {
GeneralTools.hideLoading();
dialogError.show();
}
});
Related
I want to retrieve a Json from server and pass it to WebView and consume it in a JavaScript function. So I think I dont need a Java class to hold the data and consume it in Java environment. Actually I want to omit the mediator calss (Users) I used in Retrofit. It was complicated for me to understand the structrure of retrofit request so I have no idea how to consume the response directly without a mediator class. This is my current code:
in Main Activity:
public void getUserList(){
GetUsers users = RetrofitInstance.getRetrofitInstance().create(GetUsers.class);
Call<Users> call = users.getUserList("myUsername");
call.enqueue(new Callback<Users>() {
#Override
public void onResponse(Call<Users> call, Response<Users> response) {
PassUsersToJavaScript(response.body().getList());
}
#Override
public void onFailure(Call<Users> call, Throwable t) {
Toast.makeText(MainActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});
}
public void PassUsersToJavaScript(String users){
//Here I pass users to WebView
}
This is the mediator Users class that I want to omit:
public class Users {
#SerializedName("users")
private String users;
public Users(String users) {
this.users = users;
}
public String getList(){
return users;
}
}
and this is the mediator Interface GetUsers :
public interface GetUsers {
#GET("list/")
Call<Users> getUserList(#Query("user") String user);
}
How can I omit the class Users.java and use the response.body() driectly in the line below:
public void onResponse(Call<Users> call, Response<Users> response) {
PassUsersToJavaScript(response.body().getList());
}
I found that I can assign retrofit to a class, object, page and even a string. The model class users in the question above can be replaced with anything else like this JsonObject directly:
public void getUserList(){
GetUsers users = RetrofitInstance.getRetrofitInstance().create(GetUsers.class);
Call<JsonObject> call = users.getUserList("myUsername");
call.enqueue(new Callback<JsonObject>() {
#Override
public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
PassUsersToJavaScript(response.body().getList());
}
#Override
public void onFailure(Call<JsonObject> call, Throwable t) {
Toast.makeText(MainActivity.this, "Something went wrong...Please try later!", Toast.LENGTH_SHORT).show();
}
});
}
From the server, sometimes we are getting a response that is null or empty. Because of this, our code will crash at some null pointer exception. We don't want to have null checks everywhere in code. Is there a way to specify default values when a retrofit response is null or empty? In the code below, this is how we can handle it on a case-by-case basis. But, we do not want to write this logic for every object. We want to do this somehow at the application level. Is that possible?
#SerializedName("isPdf")
#Expose
private String isPdf;
public boolean getIsPdf() {
return !Util.isNullOrEmpty(isPdf) && isPdf.equalsIgnoreCase("true") ? true : false;
}
public void setIsPDF(boolean isPdf) {
this.isPdf = isPdf ? "true" : "false";
}
You can create a default callback that handles a null response the way you want. For example, calling onFailure:
public class DefaultCallback<T> implements Callback<T> {
private static final String TAG = "YOUR_TAG";
private Callback<T> callback;
public DefaultCallback(Callback<T> callback) {
this.callback = callback;
}
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.body() == null) {
callback.onFailure(call, new NullPointerException("Empty response"));
} else {
callback.onResponse(call, response);
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
Log.e(TAG, t.toString());
callback.onFailure(call, t);
}
}
And then use this callback in your implementation.
Call<MyObject> call = ... //Create your call
call.enqueue(new DefaultCallback<>(new Callback<MyObject>() {
#Override
public void onResponse(Call<MyObject> call, Response<MyObject> response) {
//Handle successful non-null responses
}
#Override
public void onFailure(Call<MyObject> call, Throwable t) {
//Handle errors/null responses
}
}));
I am building the network structure in my android application i one of the things i realized is that i want to do is to create my own interface in my requests class .
i have this method for example :
public static void getUserData(String owner, final DataManager.OnDataReceived<Owner> listener) {
Call<Owner> call = getGitService().getUser(owner);
call.enqueue(new Callback<Owner>() {
#Override
public void onResponse(Call<Owner> call, Response<Owner> response) {
}
#Override
public void onFailure(Call<Owner> call, Throwable t) {
}
});
}
now...all my methods respond same way to the call back so why not handle this one time ?
so the way i did it it to create class that implement retrofit Callback interface :
private static class callbackHandler implements Callback {
final DataManager.OnDataReceived listener;
callbackHandler(DataManager.OnDataReceived listener) {
this.listener = listener;
}
#Override
public void onResponse(Call call, Response response) {
listener.onDataReceived(response.body(), getErrorFromResponse(response));
}
#Override
public void onFailure(Call call, Throwable t) {
listener.onDataReceived(null, t.toString());
}
}
so now all the request look like this :
public static void getUserData(String owner, final DataManager.OnDataReceived<Owner> listener) {
Call<Owner> call = getGitService().getUser(owner);
call.enqueue(new callbackHandler(listener));
}
much clearer ...
1 . what do you think about this solution ? i had better way to handle all Callback same way ?
2 . the compiler shout at me that
call.enqueue(new callbackHandler(listener));
and
#Override
public void onResponse(Call call, Response response) {
listener.onDataReceived(response.body(), getErrorFromResponse(response));
}
#Override
public void onFailure(Call call, Throwable t) {
listener.onDataReceived(null, t.toString());
}
and my interface :
public interface OnDataReceived<T> {
void onDataReceived(T data, String error);
}
is unchecked assignment...i understand what that means but not sure how to fix this ?
UPDATE : solution for the unchecked
private static class callbackHandler<T> implements Callback<T> {
final DataManager.OnDataReceived<T> listener;
callbackHandler(DataManager.OnDataReceived<T> listener) {
this.listener = listener;
}
#Override
public void onResponse(Call<T> call, Response<T> response) {
listener.onDataReceived(response.body(), getErrorFromResponse(response));
}
#Override
public void onFailure(Call<T> call, Throwable t) {
listener.onDataReceived(null, t.toString());
}
}
what do you think about this solution ?
This is called the adapter pattern. You are adapting one interface (Callback<Owner>) to another (DataManager.OnDataReceived<Owner>).
If your objective is to be able to replace Retrofit with something else in the future, this sort of adapter is perfectly reasonable. Otherwise, you might consider just having DataManager.OnDataReceived extend Callback and change your method names to match (e.g., onDataReceived() turns into onResponse()), to avoid the need for this adapter.
i understand what that means but not sure how to fix this
callbackHandler implements Callback wipes out the Java generics.
If this is only for use with Owner, use callbackHandler implements Callback<Owner> and have it hold a DataManager.OnDataReceived<Owner>. If you plan to use this for multiple model objects (assuming that Owner is a model), use callbackHandler implements Callback<T> and have it hold a DataManager.OnDataReceived<T>.
I am new to android programming and I am trying to connect to server with retrofit and get some data. I made a little example just to check if it would return some data. First there is a problem that I don't know if I even wrote the code to do what I want and second I get the errors:
"Error:(64, 52) error: is not abstract and does not override abstract method failure(RetrofitError) in Callback"
and 2 errors " Error:(67, 13) error: method does not override or implement a method from a supertype"
Here is my code
public class MainActivity extends ListActivity{
public static final String ENDPOINT = "http://tinoba.hostzi.com";
List<Jelovnik> jelovnik;
Button gumb;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
gumb = (Button)findViewById(R.id.gumb);
}
public void stisni(View view) {
RestAdapter adapter = new RestAdapter.Builder()
.setEndpoint(ENDPOINT)
.build();
JelovnikAPI api = adapter.create(JelovnikAPI.class);
api.getFeed(new Callback<List<Jelovnik>>() {
#Override
public void onResponse(Response<List<Jelovnik>> response, Retrofit retrofit) {
jelovnik = response.body();
gumb.setText(jelovnik.get(0).getIme().toString());
}
#Override
public void onFailure(Throwable throwable) {
}
});
}
}
and my retrofit interface
public interface JelovnikAPI {
#GET("/read.php")
public void getFeed(Callback<List<Jelovnik>> response);
}
The version of Callback you are using is from Retrofit 2 and you are still using Retrofit 1.x. Callback has two methods, failure and success. Your callback should look like
new Callback<List<Jelovnik>>() {
#Override
success(List<Jelovnik> t, Response response) {
}
#Override
public void failure(RetrofitError error) {
}
});
Replace Throwable with RetrofitError:
#Override
public void onFailure(RetrofitError retrofitError) {
}
This is my post :
#POST("/path")
#FormUrlEncoded
void postIt(#Field("id") String id , Callback<Response> response);
and this is the Callback:
private Callback<Response> responseCallBack = new Callback<Response>() {
#Override
public void success(Response response, Response response2) {
// get the id
}
#Override
public void failure(RetrofitError error) {
// do some thing
}
};
Question:
in the callback i want to receive the id which posted in #POST, how should i do that?
and i can't change the server API
to do this we need an abstract class
abstract class CallBackWithArgument<T> implements Callback<T> {
String arg;
CallBackWithArgument(String arg) {
this.arg = arg;
}
CallBackWithArgument() {
}
and make an instance
new CallBackWithArgument<Response>(id) {
#Override
public void success(Response response, Response response2) {
//do something
}
#Override
public void failure(RetrofitError error) {
//do something
}
}
It's easy. You can simply make Callback to hold requested id and create new callback every time
class MyCallback extends Callback<Response> {
private final String id;
MyCallback(String id) {
this.id = id
}
#Override
public void success(Response response, Response response2) {
// get the id
}
#Override
public void failure(RetrofitError error) {
// do some thing
}
}
So when you call service
myService.postIt("777", new MyCallback("777"))