I'm using Retrofit 2.0. To get some data from RESTFull services I use procedures like this:
public Call downloadUser() {
// Create RetrofitService
Call<User> call = service.getUser();
call.enqueue(new Callback<User>() {
#Override
public void onResponse(Response<User> response, Retrofit retrofit) {
// Do some operations with User obj if response.isSuccess()
}
#Override
public void onFailure(Throwable t) {
// Failure
}
});
return call;
}
In some cases, I need to cancel my request. I use call.cancel(), but even if I call this procedure Callback.onResponse(...) or Callback.onFailure(...) triggered anyway, so using Call.cancel() doesn't cancel my request and it keeps on going until failure or response.
To know if a call was canceled or if it was truly successful you'll need to two a few things.
First it looks like the version of Retrofit2 you are using needs to be updated
Second you can check if a call was canceled based on the code below. Note that this will deal with cancels from the Call<> or the Dispatcher.class in OKHttp3
#Override
public void onResponse(Response<User> response, Response response) {
if(response != null && response.isSuccessful()) {
//Do Stuff with the response
}
}
#Override
public void onFailure(Call<User> user, Throwable t) {
if(user.isCanceled() || "Canceled".equals(t.getMessage())) {
//Call was canceled
} else {
//Call failed
}
}
Related
I want to get the retrofit response list and use it outside the OnResponse function, but went I try to do it I'm always getting a null object.
Here is my source code
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<ActivitiesResponse> call = apiService.getUserActivities(id);
call.enqueue(new Callback<ActivitiesResponse>() {
// If success
#Override
public void onResponse(Call<ActivitiesResponse>call, Response<ActivitiesResponse> response) {
list = response.body().getActivities();// I'm getting a not null response
}
// If failed
#Override
public void onFailure(Call<ActivitiesResponse>call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
//When I try to use the list here I'm getting a null object
Requests are async, so when you try to return a value, the request is likely not done yet so you cannot use it outside of the request. If you want to return values from the request use callback interfaces.
Change your code to a method and pass a callback parameter
Example
public void doRequest(final ApiCallback callback) {
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<ActivitiesResponse> call = apiService.getUserActivities(id);
call.enqueue(new Callback<ActivitiesResponse>() {
// If success
#Override
public void onResponse(Call<ActivitiesResponse>call, Response<ActivitiesResponse> response) {
list = response.body().getActivities();
callback.onSuccess(list); // pass the list
}
// If failed
#Override
public void onFailure(Call<ActivitiesResponse>call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
}
public interface ApiCallback{
void onSuccess(ArrayList<YOURTYPE> result);
}
Example usage in onResume(), basically you can do this anywhere you want:
public void onResume(){
super.onResume();
doRequest(new ApiCallback(){
#Override
public void onSuccess(ArrayList<YOURTYPE> result){
//do stuff here with the list from the request
}
});
}
Let me know if this fits your needs
Because onResponse() runs asynchronously. You can not get its value like that.
You should call the method which uses list value inside onResponse().
For example.
call.enqueue(new Callback<ActivitiesResponse>() {
// If success
#Override
public void onResponse(Call<ActivitiesResponse>call, Response<ActivitiesResponse> response) {
list = response.body().getActivities();// I'm getting a not null response
yourMethod();
}
// If failed
#Override
public void onFailure(Call<ActivitiesResponse>call, Throwable t) {
// Log error here since request failed
Log.e(TAG, t.toString());
}
});
private void yourMethod() {
// list is used somewhere here
}
My call is executed but does not trigger the onResponse or onFailure method
The Json object that is returned has an image inside
This is the code in my interactor class
private ExamApi initiateRetrofit() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(ExamApi.class);
}
public void getExamImage(String user, String token,String exId, String exDocId) {
if (examApi == null) initiateRetrofit();
Call<ResponseBody> call = examApi.getExamImage(user,token,exId,exDocId);
call.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
listener.onImageSuccess(response.body());
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
//TODO ONFAILURE
//listener.onImageFailure();
listener.onFailure();
}
});
}
this is my examApi
#GET("mobile/getExamImage")
Call<ResponseBody> getExamImage(
#Query("user") String username,
#Query("token") String token,
#Query("exid") String exId,
#Query("edid") String exDocId
);
It is happening because you are making an asynchronous call on the retrofit. You are trying to capture the data even before the network call happens. This gives you a null result. Try Broadcasting the result using broadcast receiver or third party library like EventBus which will make your result available after the network call has happened.
I need make POST request with parameters "guid=1" in Body. i use Retrofit2
I try :
#POST("/api/1/model")
Call<ApiModelJson> getPostClub(#Body User body);
User Class:
public class User {
#SerializedName("guid")
String guid;
public User(String guid ) {
this.guid = guid;
}
MailActivity:
User user =new User ("1");
Call<ApiModelJson> call = service.getPostClub(user);
call.enqueue(new Callback<ApiModelJson>() {
#Override
public void onResponse(Response<ApiModelJson> response) {
}
#Override
public void onFailure(Throwable t) {
dialog.dismiss();
}
How make this request?
you have to call call.enqueue, providing an instance of Callback< ApiModelJson>, where you will get the response. enqueue executes your backend call asynchronously. You can read more about call.enqueue here
With code below, you can make the request synchronously:
ApiModelJson responseBody = call.execute();
If you want it to be asynchronous:
call.enqueue(new Callback<ApiModelJson>() {
#Override
public void onResponse(Response<ApiModelJson> response, Retrofit retrofit) {
}
#Override
public void onFailure(Throwable t) {
}
});
I want to implement a error handling mechanism using Retorfit 2.
The solutions that are available are using RetrofitError class which I can't find in the current repo.
If you are making synchronous request, you define your request method in the interface as Call<List<Car>>.
Once you execute the request you receive response and deserialized data wrapped in Response<T> as Response<List<Car>>. This wrapped gives you access to headers, http codes and raw response body.
You can access error body as:
Call<List<Car>> carsCall = carInterface.loadCars();
try {
Response<List<Car>> carsResponse = carsCall.execute();
} catch (IOException e) {
e.printStackTrace();
//network Exception is throw here
}
if(carsResponse != null && !carsResponse.isSuccess() && carsReponse.errorBody() != null){
// handle carsResponse.errorBody()
}
For async calls, you receive Throwable, if I/O exception is thrown during the network call:
Call<List<Car>> call = service.loadCars();
call.enqueue(new Callback<List<Car>>() {
#Override
public void onResponse(Response<List<Car>> response) {
// Get result from response.body(), headers, status codes, etc
}
#Override
public void onFailure(Throwable t) {
//handle error
}
});
Call<List<data>> call = MyService.loadData();
call.enqueue(new Callback<List<data>>() {
#Override
public void onResponse(Call<List<data>> call, Response<List<data>> response) {
if (response.isSuccessful()) {
//Response success. Handle data here
}
else{
//For getting error message
Log.d("Error message",response.message());
//For getting error code. Code is integer value like 200,404 etc
Log.d("Error code",String.valueOf(response.code()));
}
}
#Override
public void onFailure(Call<List<data>> call, Throwable t) {
if (t instanceof IOException){
//Add your code for displaying no network connection error
}
});
The simple method:
int code = response.raw().code();
String message = response.raw().message();
I am not able to get success response status code from response like 200,201.. etc. As we can easily get error codes from RetrofitError class like error.isNetworkError() and error.getResponse().getStatus(). Is there any workaround for getting status codes?
As per Retrofit 2.0.2, the call is now
#Override
public void onResponse(Call<YourModel> call, Response<YourModel> response) {
if (response.code() == 200) {
// Do awesome stuff
} else {
// Handle other response codes
}
}
Hope it helps someone :-)
EDIT: Many apps could also benefit from just checking for success (response code 200-300) in one clause, and then handling errors in other clauses, as 201 (Created) and 202 (Accepted) would probably lead to the same app logic as 200 in most cases.
#Override
public void onResponse(Call<YourModel> call, Response<YourModel> response) {
if (response.isSuccessful()) {
// Do awesome stuff
} else if (response.code() == 401) {
// Handle unauthorized
} else {
// Handle other responses
}
}
You can get the status code in success() just like you do it in failure()
#Override
public void success(Object object, Response response) {
response.getStatus() // returns status code integer
}
Since you have a Response object in success callback as response.getStatus()
EDIT
I assume you are using okhttp with retrofit.
okhttp has a powerful tool called Interceptor
You can catch the response before retrofits Callback and get status code from the response:
OkHttpClient client = new OkHttpClient();
client.interceptors().add(new Interceptor(){
#Override
public Response intercept(Chain chain) throws IOException{
Request request = chain.request();
Response response = chain.proceed(request);
response.code()//status code
return response;
});
// then add it to you Restclient like this:
restAdapter = new RestAdapter.Builder()
.setEndpoint(URL_SERVER_ROOT)
.setClient(new OkClient(client)) //plus your configurations
.build();
To learn more about interceptors visit here.
i achieved it by following codes:
public abstract class BaseCallBack<T> {
public abstract void onSuccess(Response<T> response);
public abstract void onFailure(Response<T> response);
}
public abstract class SuccessCallback<T> extends BaseCallBack<T> implements Callback<T>{
#Override
public void onResponse(Call<T> call, Response<T> response) {
if(response.code()>= 400 && response.code() < 599){
onFailure(response);
}
else {
onSuccess(response);
}
}
#Override
public void onFailure(Call<T> call, Throwable t){
}
#Override
public void onSuccess(Response<T> response) {
}
#Override
public void onFailure(Response<T> response) {
}
}
When the rest api returns 400 etc then the onFailure method will be call by default. If you wanna do something onsuccess:(when returns 200 etc)
ServiceConnector.api.getHomePage().enqueue(new SuccessCallback<Void>() {
#Override
public void onSuccess(Response<Void> response) {
super.onSuccess(response);
}
});
you should get exception code iin onError response
HttpException httpException =((HttpException) e).code();