I've a backend that returns 200 HTTP code even if the request had errors:
{
"error": {
"message": "Generic error",
"code": 13000
}
}
Now, how can I access raw response body, after using:
.addConverterFactory(GsonConverterFactory.create(gson))
I've tried:
response.raw().body().string()
But I get:
java.lang.IllegalStateException: Cannot read raw response body of a converted body.
I've implemented a generic APICallback class, that should "block" the success and fire an APIError event:
abstract class APICallback<T> implements Callback<T> {
abstract void onSuccess(Call<T> call, T result);
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.body() != null) {
if (response.body() instanceof APIError) {
// this is not working
} else {
onSuccess(call, response.body());
}
} else {
apiError = new APIError("Unknown error");
bus.post(new APIErrorEvent(apiError));
}
}
#Override
public void onFailure(#NonNull Call<T> call, #NonNull Throwable t) {
String message = t.getLocalizedMessage() != null ? t.getLocalizedMessage() : "Unknown error";
apiError = new APIError(message);
bus.post(new APIErrorEvent(apiError, source));
}
}
I'd like to mantain the "auto-converter" capability...many thanks in advance.
For error response you have to take response.errorBody() not response.body()
abstract class APICallback<T> implements Callback<T> {
abstract void onSuccess(Call<T> call, T result);
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.body() != null) {
if (response.body() instanceof APIError) {
// this is not working
} else {
onSuccess(call, response.body());
}
} else {
apiError = new APIError("Unknown error");
bus.post(new APIErrorEvent(apiError));
}
}
#Override
public void onFailure(#NonNull Call<T> call, #NonNull Throwable t) {
String message = t.getLocalizedMessage() != null ? t.getLocalizedMessage() : "Unknown error";
apiError = new APIError(message);
bus.post(new APIErrorEvent(apiError, source));
}
}
change to
abstract class APICallback<T> implements Callback<T> {
abstract void onSuccess(Call<T> call, T result);
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.isSuccessful()) {
if (response.body() != null) {
onSuccess(call, response.body());
}
} else {
if (response.errorBody() != null) {
if (response.errorBody() instanceof APIError) {
}
} else {
apiError = new APIError("Unknown error");
bus.post(new APIErrorEvent(apiError));
}
}
}
#Override
public void onFailure(#NonNull Call<T> call, #NonNull Throwable t) {
String message = t.getLocalizedMessage() != null ? t.getLocalizedMessage() : "Unknown error";
apiError = new APIError(message);
bus.post(new APIErrorEvent(apiError, source));
}
}
Related
I am using retrofit to retrieve data from my server - it is a user search:
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<List<Movie>> call = apiService.getSearch(lng, 0, newText);
call.enqueue(new Callback<List<Movie>>() {
#Override
public void onResponse(#NonNull Call<List<Movie>> call, #NonNull Response<List<Movie>> response) {
movieList = response.body();
if (dialog != null) {
dialog.dismiss(); dialog = null;
}
if (response.isSuccessful()) {
recyclerAdapter.setMovieList(movieList);
} else {
showMsgSnack(getString(R.string.Nodata));
}
}
#Override
public void onFailure(#NonNull Call<List<Movie>> call, #NonNull Throwable t) {
if (dialog != null) {
dialog.dismiss(); dialog = null;
}
if(t instanceof UnknownHostException){
showMsgSnack(getString(R.string.Network));
}
else if(t instanceof SocketTimeoutException){
showMsgSnack(getString(R.string.ServerTimeout));
}
else {
showMsgSnack(getString(R.string.ServerError));
}
}
});
Json is generaed via PHP in the server. If the search is success, json will return like [{"title": "sometitle",...}].
But if there is no match in database, I am returning just an empty {}.
But in android it goes to the failure and shows ServerError message. I want to show in that case some message as No match found.
How can I handle this response?
I also created a Default callback for Nullpointerexception, but this still doesn't work:
call.enqueue(new DefaultCallback<>(new Callback<List<Movie>>() {
#Override
public void onResponse(#NonNull Call<List<Movie>> call, #NonNull Response<List<Movie>> response) {
movieList = response.body();
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
if (response.isSuccessful()) {
recyclerAdapter.setMovieList(movieList);
} else {
showMsgSnack(getString(R.string.Nodata));
}
}
#Override
public void onFailure(#NonNull Call<List<Movie>> call, #NonNull Throwable t) {
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
if (t instanceof UnknownHostException) {
showMsgSnack(getString(R.string.Network));
}
if (t instanceof NullPointerException) {
showMsgSnack(getString(R.string.Nodata));
} else if (t instanceof SocketTimeoutException) {
showMsgSnack(getString(R.string.ServerTimeout));
} else {
showMsgSnack(getString(R.string.ServerError));
}
}
}));
}
public static class DefaultCallback<T> implements Callback<T> {
private static final String TAG = "YOUR_TAG";
private final Callback<T> callback;
public DefaultCallback(Callback<T> callback) {
this.callback = callback;
}
#Override
public void onResponse(#NonNull 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(#NonNull Call<T> call, Throwable t) {
Log.e(TAG, t.toString());
callback.onFailure(call, t);
}
}
It says: YOUR_TAG: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $
In android after receiving response from API you want List of type Movie object (List) which is like [{"title": "sometitle",...}] this.
But when you don't find anything on search then you are returning " {} "
And here you are getting an issue, this is because you are excepting List means Array and API returning "{}" means Object.
Simple solution don't send object "{}" send Array "[]" and check
#Override
public void onResponse(#NonNull Call<List<Movie>> call, #NonNull Response<List<Movie>> response) {
movieList = response.body();
if (dialog != null) {
dialog.dismiss();
dialog = null;
}
if (movieList.size() > 0) {
recyclerAdapter.setMovieList(movieList);
} else {
showMsgSnack(getString(R.string.Nodata));
}
}
Hope you understand and this will help!
I'm using the MVVM architecture, i have my model class "Category" and my ViewModel class and the MainActivity and Adapter for Recyclerview ,
All is works fine if i set the adapter inside the activity (inside onResponse methode of the Retrofit Call), but if i do it this way im not respecting the separation of the MVVM architecture,
here is the methode that use to excute the call :
public List<Category> getcategories() {
RestInterface restInterface = rest.getInterfaceService();
Call<List<Category>> productService = restInterface.getCategories();
productService.enqueue(new Callback<List<Category>>() {
#Override
public void onResponse(Call<List<Category>> call, Response<List<Category>> response) {
if (response.body() == null){
Log.e(TAG, "responce Call response is null ");
}else{
Log.e(TAG, "repo : "+response.body().toString());
categories = (ArrayList<Category>) response.body();
}
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
Log.e(TAG, "Call Fail : " + t.getMessage());
}
});
Log.e(TAG, "repo 2: "+categories.toString());
return categories;
}
here is the logcat results :
07-11 20:18:34.325 24369-24369/com.instadom E/DataRepository: repo 2: []
07-11 20:18:35.399 24369-24369/com.instadom E/DataRepository: repo : [exemple.com.models.Category#1df175e, exemple.com.models.Category#5cfc73f, exemple.com.models.Category#1e7380c, exemple.com.models.Category#7ceb555, exemple.com.models.Category#3014b6a, exemple.com.models.Category#a83985b, exemple.com.models.Category#3d5c8f8, exemple.com.models.Category#d1251d1]
what i can't understand is why i don't get any result in the "Log.e(TAG, "repo 2: "+categories.toString());" even tho "categories" is a class object
I would apreciate any help,
thanks in advance,
Here is the code :
public List getcategories(final Callback>
callback) {
RestInterface restInterface = rest.getInterfaceService();
Call> productService = restInterface.getCategories();
productService.enqueue(new retrofit2.Callback>() {
#Override
public void onResponse(Call> call, Response> response) {
if (response.body() == null){
Log.e(TAG, "responce Call response is null ");
}else{
Log.e(TAG, "repo : "+response.body().toString());
categories = (ArrayList) response.body();
callback.onSuccess(categories);
}
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
Log.e(TAG, "Call Fail : " + t.getMessage());
callback.onFailure(t.getMessage());
}
});
Log.e(TAG, "result : "+categories.toString());
return categories;
}
public interface Callback<T> {
void onSuccess(ArrayList<Category> data);
void onFailure(String reason);
}
here is the error :
java.lang.NullPointerException: Attempt to invoke interface method 'void instadom.com.repositories.DataRepository$Callback.onSuccess(java.util.ArrayList)' on a null object reference
That is because productService.enqueue is an asynchronous call, The statement Log.e(TAG, "repo 2: "+categories.toString()); will be executed right after the call is is enqued and the onResponse or onFailure will be executed after a network call. pass in a callback to the getCategories() to get the category list like this
public interface Callback<List<Categories>> callback{
void onSuccess(List<Categories> data);
void onFailure(String reason);
}
or you can use a generic callback interface to use in all your network requests like this
public interface Callback<T> callback{
void onSuccess(List<T> data);
void onFailure(String reason);
}
then implement the callback functionality
public List<Category> getcategories(Callback<List<Category>> callback) {
RestInterface restInterface = rest.getInterfaceService();
Call<List<Category>> productService = restInterface.getCategories();
productService.enqueue(new Callback<List<Category>>() {
#Override
public void onResponse(Call<List<Category>> call, Response<List<Category>> response) {
if (response.body() == null){
Log.e(TAG, "responce Call response is null ");
}else{
Log.e(TAG, "repo : "+response.body().toString());
categories = (ArrayList<Category>) response.body();
callback.onSuccess(categories);
}
}
#Override
public void onFailure(Call<List<Category>> call, Throwable t) {
Log.e(TAG, "Call Fail : " + t.getMessage());
callback.onError(t.getMessage());
}
});
}
I need to handle a functionality based on the retrofit response.
The post method has the request as json format and getting the response as Text true
I have tried to get this response as the following code snippet. But always I get false though I get true in postman response.
private void callPostLoginAPI(String webServiceResponse) {
ApiInterface apiService = ApiClient.getClient().create(ApiInterface.class);
Call<ResponseBody> result = apiService.getPostDealer(postLoginAPI(webServiceResponse));
result.enqueue(new Callback<ResponseBody>() {
#Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
String postLoginResponse = null;
try {
postLoginResponse = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
if (postLoginResponse != null || (!postLoginResponse.equals(""))) {
if (postLoginResponse.equals("true")) {
try {
if (PreferenceClass.getInstallationID(Loginpage.this) == null ||
PreferenceClass.getInstallationID(Loginpage.this).equals("")) {
request_appInstallation_API(0);
} else {
checkAppUpdate();
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
Toast.makeText(Loginpage.this, "Please contact CMS Admin", Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(Loginpage.this, "Something went wrong... Please try again", Toast.LENGTH_LONG).show();
}
}
#Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
Toast.makeText(Loginpage.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
UPDATE:
As I tried the following,and I havent gotten the respective "Postman response value" .
ApiInterface apiService = ApiClient.getClient1().create(ApiInterface.class);
Call<Boolean> result = apiService.getPostDealer(postLoginAPI(webServiceResponse));
result.enqueue(new Callback<Boolean>() {
#Override
public void onResponse(Call<Boolean> call, Response<Boolean> response) {
Log.i("Response", response.body().toString());
if (response.isSuccessful()) {
if (response.body() != null) {
Log.i("callPostLoginAPI", response.body().toString());
Toast.makeText(Dealer_Loginpage.this, "returned", Toast.LENGTH_LONG).show();
} else {
Toast.makeText(Dealer_Loginpage.this, "Nothing returned", Toast.LENGTH_LONG).show();
}
}
}
#Override
public void onFailure(Call<Boolean> call, Throwable t) {
Toast.makeText(Dealer_Loginpage.this, "Nothing returned", Toast.LENGTH_LONG).show();
}
});
ApiClient.getClient1() :
public static Retrofit getClient1() {
if (retrofit1 == null) {
retrofit1 = new Retrofit.Builder().baseUrl(GlobalClass.sBase_Url).
addConverterFactory(ScalarsConverterFactory.create()).
addConverterFactory(GsonConverterFactory.create()).build();
}
return retrofit1;
}
Solution:
Attach this:
postLoginResponse.replaceAll("[^A-Za-z]+", "");
After the line:
postLoginResponse = response.body().string();
and try.
i'm working on API integration. i want to make generic class for API integration. which can comfortable with for all API integration.right now i'm using separate code for all API. i'm new in android application development. so please guide me.
public void getHomeCategoryDetailApi(Context context) {
final ProgressDialog loadingDialog = ProgressDialog.show(context, "Please wait", "Loading...");
Retrofit restAdapter = ApiLists.retrofit;
ApiLists apiCall = restAdapter.create(ApiLists.class);
Call<HomeCategoryModelClass> call = apiCall.homePageCatListAPI();
Log.d(TAG, "CategoryDetail : " + call.request()+" \n"+apiCall.homePageCatListAPI().toString());
call.enqueue(new Callback<HomeCategoryModelClass>() {
#Override
public void onResponse(Call<HomeCategoryModelClass> call, Response<HomeCategoryModelClass> response) {
Log.d(TAG, "onResponse: CategoryDetail:" + response.body());
Log.d(TAG, "onResponse: response.code():" + response.code());
if (response.body() == null) {
loadingDialog.dismiss();
globalClass.showAlertDialog(getActivity(), getString(R.string.InternetAlert), getString(R.string.InternetMessage), false);
} else {
loadingDialog.dismiss();
if (response.body().getStatusCode().equalsIgnoreCase("1")) {
homeCategoryImageMenu = (ArrayList<Menu>) response.body().getMenu();
thirdHorizontalRecyclerAdapter.notifyDataSetChanged();
} else {
globalClass.showAlertDialog(getActivity(), "Alert", "" + response.body().getStatus(), false);
}
}
if (response.errorBody() != null) {
try {
Log.d(TAG, "onResponse: response.errorBody()===>" + response.errorBody().string());
if (loadingDialog.isShowing() && loadingDialog != null) {
loadingDialog.dismiss();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<HomeCategoryModelClass> result, Throwable t) {
Log.d(TAG, "onFailure: " + result.toString());
loadingDialog.dismiss();
globalClass.showAlertDialog(getActivity(), getString(R.string.InternetAlert), getString(R.string.InternetMessage), false);
}
});
}
Here is Bast Way to call API
public class APIResponse {
private static String TAG = APIResponse.class.getSimpleName();
public static <T> void callRetrofit(Call<T> call, final String strApiName, Context context, final ApiListener apiListener) {
final ProgressDialog progressDialog = new ProgressDialog(context);
progressDialog.setMessage("Loading...");
progressDialog.setCancelable(false);
progressDialog.show();
call.enqueue(new Callback<T>() {
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (strApiName.equalsIgnoreCase("LoginApi")) {
if (response.isSuccessful()) {
Log.d(TAG, "onResponse: " + response.body().toString());
// NearByNurse nearByNurse = (NearByNurse) response.body(); // use the user object for the other fields
// apiListener.success(url,nearByNurse);
progressDialog.dismiss();
} else {
try {
Log.d(TAG, "onResponse: " + response.errorBody().string());
apiListener.error(strApiName, response.errorBody().string());
progressDialog.dismiss();
} catch (IOException e) {
e.printStackTrace();
}
}
} else if (strApiName.equalsIgnoreCase("")) {
//Patient user = (Patient) response.body();
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
Log.d(TAG, "onFailure: " + t.toString());
if (strApiName.equalsIgnoreCase("searchNearbyTest")) {
apiListener.failure(strApiName, t.toString());
}
progressDialog.dismiss();
}
});
}
In API Calling Side
private void loginApi() {
Retrofit retrofit = ApiLists.retrofit;
ApiLists apiList = retrofit.create(ApiLists.class);
Call<JsonElement> loginApiCall = apiList.loginApi("kjdf", "fkldngdkl", "lkfdxngl", "kjngn", "jksdgkj");
APIResponse.callRetrofit(loginApiCall, "LoginApi", LoginActivity.this, this);
}
#Override
public void success(String strApiName, Object response) {
if (strApiName.equals("LoginApi")) {
}
}
#Override
public void error(String strApiName, String error) {
if (strApiName.equals("LoginApi")) {
}
}
#Override
public void failure(String strApiName, String message) {
if (strApiName.equals("LoginApi")) {
}
and interface call on API response.
public interface ApiListener {
void success(String strApiName, Object response);
void error(String strApiName, String error);
void failure(String strApiName, String message);
}
This's my common function basic call Api.java
public class Api {
private void basicCall(Call<DataResponse> call) {
if (call == null) {
listener.onResponseCompleted(Config.STATUS_404, "404 not found", null);
return;
}
call.enqueue(new Callback<DataResponse>() {
#Override
public void onResponse(#NonNull Call<DataResponse> call, #NonNull Response<DataResponse> response) {
int code = response.code();
//Check http ok
if (code == HttpURLConnection.HTTP_OK) {
//Check status
if (response.body().getStatus() == Config.STATUS_OK) {
//Everything's OK
listener.onResponseCompleted(Config.STATUS_OK, response.body().getError(), response.body().getData());
} else {
listener.onResponseCompleted(Config.STATUS_FAILED, response.body().getError(), null);
}
} else if (code == HttpURLConnection.HTTP_UNAUTHORIZED) {
try {
ErrorResponse error = Api.gson.fromJson(response.errorBody().string(), ErrorResponse.class);
listener.onResponseCompleted(Config.STATUS_401, error.getError(), error.getData());
} catch (IOException e) {
e.printStackTrace();
}
} else {
listener.onResponseCompleted(Config.STATUS_404, "404 not found", null);
}
}
#Override
public void onFailure(#NonNull Call<DataResponse> call, #NonNull Throwable t) {
listener.onResponseCompleted(Config.STATUS_404, "404 not found", null);
}
});
}
//And you can use
public void getProductList(OnResponseCompleted listener) {
this.listener = listener;
Call<DataResponse> call = apiService.getProductList();
basicCall(call);
}
}
//or orther function
This's ApiService.java
public interface ApiInterface {
#POST("product/list")
Call<DataResponse> getProductList();
}
This's OnResponseCompleted.java
public interface OnResponseCompleted {
void onResponseCompleted(int status, String error, Object data);
}
i want to make like this .i just pass some require parameter....
public void showAlertDialog(Context context, String title, String message,
Boolean status) {
AlertDialog alertDialog = new AlertDialog.Builder(context).create();
alertDialog.setTitle(title);
// Set Dialog Message
alertDialog.setMessage(message);
alertDialog.setCancelable(false);
if (status != null)
// Set alert dialog icon
alertDialog.setIcon((status) ? R.drawable.ic_success : R.drawable.ic_fail);
// Set OK Button
alertDialog.setButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
});
// Show Alert Message
alertDialog.show();
}
Try this code..
In this code Retrofit object set up done in one class and all api calling into interface..
public class ApiClient {
private final static String BASE_URL = "https://api.github.com";
public static ApiClient apiClient;
private Retrofit retrofit = null;
public static ApiClient getInstance() {
if (apiClient == null) {
apiClient = new ApiClient();
}
return apiClient;
}
//private static Retrofit storeRetrofit = null;
public Retrofit getClient() {
return getClient(null);
}
private Retrofit getClient(final Context context) {
HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder client = new OkHttpClient.Builder();
client.readTimeout(60, TimeUnit.SECONDS);
client.writeTimeout(60, TimeUnit.SECONDS);
client.connectTimeout(60, TimeUnit.SECONDS);
client.addInterceptor(interceptor);
client.addInterceptor(new Interceptor() {
#Override
public okhttp3.Response intercept(Chain chain) throws IOException {
Request request = chain.request();
return chain.proceed(request);
}
});
retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.client(client.build())
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit;
}
}
after that call the api into api interface..
public interface ApiInterface {
#GET("{affenpinscher}/images")
Call<Product> getProductData(#Path("affenpinscher") String breed);
#GET("getProductDetailByProductId?ProductId=3")
Call<JsonObject> ITEM_DESCRIPTION_RESPONSE_CALL();
#POST("linke")
Call<Response> passJsonData(#Body JsonData jsonData);
#GET("/users/waadalkatheri/repos")
Call<Response> getdata();
}
and when you call api in activity or fragment used below code..
ApiInterface apiInterface = ApiClient.getInstance().getClient().create(ApiInterface.class);
Call<ResponseData> responseCall = apiInterface.getdata();
responseCall.enqueue(new Callback<ResponseData>() {
#Override
public void onResponse(Call<ResponseData> call, retrofit2.Response<ResponseData> response) {
if (response.isSuccessful() && response.body() != null && response != null) {
Toast.makeText(getApplicationContext(), "GetData" + response.body().getLanguage(), Toast.LENGTH_SHORT).show();
}
}
#Override
public void onFailure(Call<ResponseData> call, Throwable t) {
Log.d("Errror", t.getMessage());
}
});
I have been developing android app, wheream using Retrofit.
In that how to handle onFailure(Throwable t) callback for NoInternetConnection and OtherError
I have check some questions on stackoverflow, but it didn't helped, because am using retrofit 2
compile 'com.squareup.retrofit2:retrofit:2.1.0'
Callback Code
public class AvsCallBack<T> implements Callback<T> {
private static final String TAG = "AvsCallBack";
private AvsCallbackInterface<T> avsInterface;
private Activity activity;
private boolean validateError = true;
public AvsCallBack(Activity activity, AvsCallbackInterface<T> avsInterface) {
this.activity = activity;
this.avsInterface = avsInterface;
}
public AvsCallBack(Activity activity, AvsCallbackInterface<T> avsInterface, boolean validateError) {
this.activity = activity;
this.avsInterface = avsInterface;
this.validateError = validateError;
}
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (response.isSuccessful()) {
if (BuildConfig.DEBUG) Log.d(TAG, new Gson().toJson(response.body()));
avsInterface.onSuccess(call, response.body());
} else {
onFailure(call, null);
}
}
#Override
public void onFailure(Call<T> call, Throwable t) {
if (validateError) {
if (BuildConfig.DEBUG)
Log.d(TAG, "Retrofit Exception -> " + ((t != null && t.getMessage() != null) ? t.getMessage() : "---"));
if (t != null && (t instanceof IOException || t instanceof SocketTimeoutException || t instanceof ConnectException)) {
if (t instanceof SocketTimeoutException || t instanceof TimeoutException) {
((BaseActivity) activity).showToast("Oops something went wrong");
//avsInterface.onError(call, new AvsException("Oops something went wrong, please try again later..."));
} else {
((BaseActivity) activity).showToast("Please check your internet connection...");
//avsInterface.onError(call, new AvsException("Please check your internet connection..."));
}
} else {
((BaseActivity) activity).showToast("Oops something went wrong");
}
if (BuildConfig.DEBUG)
Log.d(TAG, "Avs Exception -> " + ((t != null && t.getMessage() != null) ? t.getMessage() : "---"));
}
avsInterface.onError(call, t);
}
}
MyInterface
public interface AvsCallbackInterface<T> {
void onSuccess(Call<T> call, T t);
void onError(Call<T> call, Throwable throwable);
}
Quote from here:
When Throwable is passed to the failure, the callback is an
IOException, this means that it was a network problem (socket
timeout, unknown host, etc.). Any other exception means something
broke either in serializing/deserializing the data or it's a
configuration problem.
You can do t instanceof IOException to determine network problem and
react appropriately.
A 401 (or any non-2xx response code) will actually go to the response
callback, because it was a successful response even though it may not
have been a successful operation on the server. You can check this in
onResponse by calling response.isSuccess().
What I do is use a interceptor for request which checks for internet connectivity and responds accordingly. In my case I use MPV so it automatically call BasePresenter method.
Interceptor:
class NetworkStatusInterceptor implements Interceptor {
#Override
public Response intercept(Chain chain) throws IOException {
if (!Util.isInternet(mContext)) {
return new Response.Builder()
.code(1007)
.request(chain.request())
.protocol(Protocol.HTTP_2)
.body(ResponseBody.create(MediaType.parse("{}"),"{}"))
.message(mContext.getString(R.string.warning_no_internet))
.build();
}
return chain.proceed(chain.request());
}
}
Attach interceptor to OkHTTPClient:
builder.addInterceptor(new NetworkStatusInterceptor());
You can handle this in your onResponse:
public void onResponse(final Call<T> call, final Response<T> response) {
if (response.code() == 1007) {
// handle no internet error
}
}