I am new to RxJava so please forgive me if this sounds too newbie :-).
As of now I have an abstract CallbackClass that implements the Retofit Callback. There I catch the Callback's "onResponse" and "onError" methods and handle various error types before finally forwarding to the custom implemented methods.
I also use this centralized class to for request/response app logging and other stuff.
For example: for specific error codes from my sever I receive a new Auth token in the response body, refresh the token and then clone.enqueue the call.
There are of course several other global behaviors to the responses from my server.
Current solution (Without Rx):
public abstract void onResponse(Call<T> call, Response<T> response, boolean isSuccess);
public abstract void onFailure(Call<T> call, Response<T> response, Throwable t, boolean isTimeout);
#Override
public void onResponse(Call<T> call, Response<T> response) {
if (_isCanceled) return;
if (response != null && !response.isSuccessful()) {
if (response.code() == "SomeCode" && retryCount < RETRY_LIMIT) {
TokenResponseModel newToken = null;
try {
newToken = new Gson().fromJson(new String(response.errorBody().bytes(), "UTF-8"), TokenResponseModel.class);
} catch (Exception e) {
e.printStackTrace();
}
SomeClass.token = newToken.token;
retryCount++;
call.clone().enqueue(this);
return;
}
}
} else {
onResponse(call, response, true);
removeFinishedRequest();
return;
}
onFailure(call, response, null, false);
removeFinishedRequest();
}
#Override
public void onFailure(Call<T> call, Throwable t) {
if (_isCanceled) return;
if (t instanceof UnknownHostException)
if (eventBus != null)
eventBus.post(new NoConnectionErrorEvent());
onFailure(call, null, t, false);
removeFinishedRequest();
}
My question is: Is there any way to have this sort of centralized response handling behavior before finally chaining (or retrying) back to the subscriber methods?
I found these 2 links which both have a nice starting point but not a concrete solution. Any help will be really appreciated.
Forcing request retry after custom API exceptions in RxJava
Retrofit 2 and RxJava error handling operators
Two links you provided are a really good starting point, which I used to construct solution to react to accidental
network errors happen sometimes due to temporary lack of network connection, or switch to low throughtput network standard, like EDGE, which causes SocketTimeoutException
server errors -> happen sometimes due to server overload
I have overriden CallAdapter.Factory to handle errors and react appropriately to them.
Import RetryWithDelayIf from the solution you found
Override CallAdapter.Factory to handle errors:
public class RxCallAdapterFactoryWithErrorHandling extends CallAdapter.Factory {
private final RxJavaCallAdapterFactory original;
public RxCallAdapterFactoryWithErrorHandling() {
original = RxJavaCallAdapterFactory.create();
}
#Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit));
}
public class RxCallAdapterWrapper implements CallAdapter<Observable<?>> {
private final Retrofit retrofit;
private final CallAdapter<?> wrapped;
public RxCallAdapterWrapper(Retrofit retrofit, CallAdapter<?> wrapped) {
this.retrofit = retrofit;
this.wrapped = wrapped;
}
#Override
public Type responseType() {
return wrapped.responseType();
}
#SuppressWarnings("unchecked")
#Override
public <R> Observable<?> adapt(final Call<R> call) {
return ((Observable) wrapped.adapt(call)).onErrorResumeNext(new Func1<Throwable, Observable>() {
#Override
public Observable call(Throwable throwable) {
Throwable returnThrowable = throwable;
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
returnThrowable = httpException;
int responseCode = httpException.response().code();
if (NetworkUtils.isClientError(responseCode)) {
returnThrowable = new HttpClientException(throwable);
}
if (NetworkUtils.isServerError(responseCode)) {
returnThrowable = new HttpServerException(throwable);
}
}
if (throwable instanceof UnknownHostException) {
returnThrowable = throwable;
}
return Observable.error(returnThrowable);
}
}).retryWhen(new RetryWithDelayIf(3, DateUtils.SECOND_IN_MILLIS, new Func1<Throwable, Boolean>() {
#Override
public Boolean call(Throwable throwable) {
return throwable instanceof HttpServerException
|| throwable instanceof SocketTimeoutException
|| throwable instanceof UnknownHostException;
}
}));
}
}
}
HttpServerException is just a custom exception.
Use it in Retrofit.Builder
Retrofit retrofit = new Retrofit.Builder()
.addCallAdapterFactory(new RxCallAdapterFactoryWithErrorHandling())
.build();
Extra: If you wish to parse errors that come from API (error that don't invoke UnknownHostException, HttpException or MalformedJsonException or etc.) you need to override Factory and use custom one during building Retrofit instance. Parse the response and check if it contains errors. If yes, then throw error and error will be handled inside the method above.
have you consider using the rxjava adapter for retrofit?
https://mvnrepository.com/artifact/com.squareup.retrofit2/adapter-rxjava/2.1.0
in your gradle file add
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
here's a interface for retrofit
public interface Service {
#GET("userauth/login?")
Observable<LoginResponse> getLogin(
#Query("v") String version,
#Query("username") String username,
#Query("password") String password);
}
and here's my implementation
Service.getLogin(
VERSION,
"username",
"password")
.subscribe(new Subscriber<LoginResponse>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
}
#Override
public void onNext(LoginResponse loginResponse) {
}
});
please note I'm using the gson converter factory to parse my response so I get an pojo (Plain Ole Java Object) returned.
See how you can do it.
Here is api call and pass Request model and response model in this.
public interface RestService {
//SEARCH_USER
#POST(SEARCH_USER_API_LINK)
Observable<SearchUserResponse> getSearchUser(#Body SearchUserRequest getSearchUserRequest);
}
This is the retrofit call,I used retrofit2
public RestService getRestService() {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ApiConstants.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.client(getOkHttpClient())
.build();
return retrofit.create(RestService.class);
}
//get OkHttp instance
#Singleton
#Provides
public OkHttpClient getOkHttpClient() {
HttpLoggingInterceptor httpLoggingInterceptor = new HttpLoggingInterceptor();
httpLoggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(httpLoggingInterceptor);
builder.readTimeout(60, TimeUnit.SECONDS);
builder.connectTimeout(60, TimeUnit.SECONDS);
return builder.build();
}
This is the api call, call it in your activity.
#Inject
Scheduler mMainThread;
#Inject
Scheduler mNewThread;
//getSearchUser api method
public void getSearchUser(String user_id, String username) {
SearchUserRequest searchUserRequest = new SearchUserRequest(user_id, username);
mObjectRestService.getSearchUser(searchUserRequest).
subscribeOn(mNewThread).
observeOn(mMainThread).
subscribe(searchUserResponse -> {
Timber.e("searchUserResponse :" + searchUserResponse.getResponse().getResult());
if (isViewAttached()) {
getMvpView().hideProgress();
if (searchUserResponse.getResponse().getResult() == ApiConstants.STATUS_SUCCESS) {
} else {
}
}
}, throwable -> {
if (isViewAttached()) {
}
});
}
Hope this will help you.
Related
I have a Restful API whos return a Java Object for me. When return that object it is still empty, because the async thread is still working. How can get that response and return then to my Presenter and it directs the correct response to the view?
That is my retrofit call:
public String checkUser(final ModelUser modelUser) throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(UserRetrofitAPI.BASE_SERVICE)
.addConverterFactory(GsonConverterFactory.create())
.build();
UserRetrofitAPI userRetrofitAPI = retrofit.create(UserRetrofitAPI.class);
Call<ModelUser> requestCheckUser = userRetrofitAPI.checkUser(modelUser.getUser(), modelUser.getPassword());
requestCheckUser.enqueue(new Callback<ModelUser>() {
#Override
public void onResponse(Call<ModelUser> call, retrofit2.Response<ModelUser> response) {
if(!response.isSuccessful()){
myModelUser = new ModelUser(modelUser.getUser(),modelUser.getPassword(), String.valueOf(response.code()));
} else {
ModelUser modelUserChecked = response.body();
myModelUser = modelUserChecked;
}
}
#Override
public void onFailure(Call<ModelUser> call, Throwable t) {
Exception ex = new Exception(t);
myModelUser = new ModelUser(modelUser.getUser(), modelUser.getPassword(), ex.toString());
}
});
return myModelUser.getResponse();
}
when I do this debugging, it works, by processing time.
help me?
You shouldn't return that directly.
As you mentioned Retrofit response is updated in background thread.
I would suggest to return requestCheckUser only and observe that in your Presenter
public Call<ModelUser> checkUser(final ModelUser modelUser) throws IOException {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(UserRetrofitAPI.BASE_SERVICE)
.addConverterFactory(GsonConverterFactory.create())
.build();
UserRetrofitAPI userRetrofitAPI = retrofit.create(UserRetrofitAPI.class);
Call<ModelUser> requestCheckUser = userRetrofitAPI.checkUser(modelUser.getUser(), modelUser.getPassword());
return requestCheckUser;
}
Observe response of that call in Presenter and perform required operations as follows
checkUser(modelUser).enqueue(new Callback<ModelUser>() {
#Override
public void onResponse(Call<ModelUser> call, retrofit2.Response<ModelUser> response) {
if(!response.isSuccessful()){
myModelUser = new ModelUser(modelUser.getUser(),modelUser.getPassword(), String.valueOf(response.code()));
} else {
ModelUser modelUserChecked = response.body();
myModelUser = modelUserChecked;
}
}
#Override
public void onFailure(Call<ModelUser> call, Throwable t) {
Exception ex = new Exception(t);
myModelUser = new ModelUser(modelUser.getUser(), modelUser.getPassword(), ex.toString());
}
});
This would be the simple option and will satisfy this use case and scope.
You can use custom Interface Listeners if you don't prefer to write observer in Presenter.
I would recommend to look into RxJava and use it with Retrofit to convert this into more maintainable code
I have this method that I am trying to pull data from an API, and then update the text view. Everything works except getRecipeName doesn't finish after the "end Method" log. .getRecipeName() uses RetroFit to pull from an API.
I am currently learning MVP, Dagger, RxJava, and Butterknife all at once using
Mindork's Github page on MVP Architecture
I commented out the .subscribeOn and .observeOn to see the result difference and nothing changed.
#Override
public void onRandomButtonClicked() {
getMvpView().showLoading();
Log.e(TAG, "Random Method Open");
getCompositeDisposable().add(getDataManager()
.getRecipeName()
//.subscribeOn(getSchedulerProvider().io())
//.observeOn(getSchedulerProvider().ui())
.subscribe(new Consumer<String>() {
#Override
public void accept(String s) throws Exception {
Log.e(TAG, "accept");
getMvpView().updateTextView(title);
}
}));
Log.e(TAG, "end method");
}
Here is my getRecipeName() method
#Override
public Observable<String> getRecipeName() {
/*Create handle for the RetrofitInstance interface*/
GetDataService service = RetrofitClientInstance.getRetrofitInstance().create(GetDataService.class);
Call<RecipeList> call = service.getRecipe();
call.enqueue(new Callback<RecipeList>() {
#Override
public void onResponse(#NonNull Call<RecipeList> call, #NonNull retrofit2.Response<RecipeList> response) {
Log.e("onResponse","Recipe is Successful = " + response.isSuccessful());
//if response is false then skip to avoid null object reference
if (response.isSuccessful()) {
RecipeList drinkRecipe = response.body();
List<Recipe> recipes = drinkRecipe.getDrinks();
jokeText = String.valueOf(recipes.size());
Recipe myRecipe = recipes.get(0);
jokeText = myRecipe.getStrDrink();
Log.e("On Response", "Result2: " + jokeText);
}
//jokeText = "null";
}
#Override
public void onFailure(Call<RecipeList> call, Throwable t) {
Log.e("On Response","Failure");
}
});
//return jokeText;
return Observable.fromCallable(new Callable<String>() {
#Override
public String call() throws Exception {
return jokeText;
}
});
}
Solution
So as the comments stated RxJava Adapter was the correct way to go. I will just post my working code on myself using the adapter. I found it very difficult to find a working example.
//single api call using retrofit and rxjava
#SuppressLint("CheckResult")
private void getRandomButtonClick(){
retrofit = RetrofitClientInstance.getRetrofitInstance();
retrofit.create(GetDataService.class).getRecipe()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(this::handleResults, this::handleError );
}
private void handleResults(RecipeList recipeList) {
int i = recipeList.getDrinks().size();
Log.e(TAG, "size is: "+ i);
Recipe recipe = recipeList.getDrinks().get(0);
getMvpView().updateTextView(recipe.getStrDrink());
}
private void handleError(Throwable t){
Log.e("Observer", "");
}
My Retrofit Client Instance
public static Retrofit getRetrofitInstance() {
if (retrofit == null) {
retrofit = new retrofit2.Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
return retrofit;
}
My Interface
public interface GetDataService {
//#Headers({})
#GET("random.php")
Observable<RecipeList> getRecipe();
I found a great resource to reference for me to correctly implement this. Retrofit Android
The reason is because your observable is returning jokeText every time it is subscribed upon. It returns immediately after invocation and will not wait for your network operation.
One possible solution is to use the RxJavaCallAdapter. Link here: https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2
It will automatically convert your API returns to observables. No need to manually invoke retrofit requests. Just process the response and convert it to your desired object from there.
Another approach would be to wrap your entire sequence in an Observable.create or Observable.fromAsync.
I am currently developing android app which uses Retrofit & OkHttpClient to get/send data from the server.
That was great when calling my own server, while it runs into 404 error when trying to call google map api.
The following represents response with error.
Response{protocol=h2, code=404, message=, url=https://maps.googleapis.com/maps%2Fapi%2Fgeocode%2Fjson%3Fkey=defesdvmdkeidm&latlng=11.586215,104.893197}
This is obviously because '/' and '?' was encoded into "%2F" and "%3F".
The solution could be prevent urlencode for those special characters, but couldn't make it.
What I tried is add custom header "Content-Type:application/x-www-form-urlencoded; charset=utf-8" to OkHttpClient via intercepter but that does not work.
Best detailed response will be appreciated.
Regards.
private Retrofit createRetrofit(OkHttpClient client, String _baseUrl) {
return new Retrofit.Builder()
.baseUrl(_baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(client)
.build();
}
private Retrofit createGoogleRetrofit() {
return createRetrofit(createGoogleClient(), baseUrl);
}
public DenningService getGoogleService() {
_baseUrl = "https://maps.googleapis.com/";
final Retrofit retrofit = createGoogleRetrofit();
return retrofit.create(DenningService.class);
}
public interface DenningService {
#GET("{url}")
#Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(#Path("url") String url);
}
private void sendRequest(final CompositeCompletion completion, final ErrorHandler errorHandler) {
mCompositeDisposable.add(mSingle.
subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.map(new Function() {
#Override
public JsonElement apply(JsonElement jsonElement) throws Exception {
return jsonElement;
}
})
.subscribeWith(new DisposableSingleObserver() {
#Override
public void onSuccess(JsonElement jsonElement) {
completion.parseResponse(jsonElement);
}
#Override
public void onError(Throwable e) {
if (e instanceof HttpException && ((HttpException) e).code() == 410) {
errorHandler.handleError("Session expired. Please log in again.");
} else {
errorHandler.handleError(e.getMessage());
}
e.printStackTrace();
}
})
);
}
public void sendGoogleGet(String url, final CompositeCompletion completion) {
mSingle = getGoogleService().getEncodedRequest(url);
sendRequest(completion, new ErrorHandler() {
#Override
public void handleError(String error) {
ErrorUtils.showError(context, error);
}
});
}
The problem is in the definition of your Retrofit service interface and the values you pass to it.
public interface DenningService {
#GET("{url}")
#Headers("Content-Type:application/x-www-form-urlencoded; charset=utf-8")
Single getEncodedRequest(#Path("url") String url);
}
From what you've posted, I'm going to assume the value of url is:
maps/api/geocode/json?key=defesdvmdkeidm&latlng=11.586215,104.893197
Here's how it should look:
public interface DenningService {
#FormUrlEncoded
#GET("/maps/api/geocode/json")
Single getEncodedRequest(#Field("key") String key,
#Field("latlng") String latlng);
}
And then you'd call it like this:
mSingle = getGoogleService().getEncodedRequest(key, latlng);
Of course, you will have to figure out how to separate the key and latlng parameters out of the current url string.
Edit
It's not obvious to me whether or not you actually want your request to be application/x-www-form-urlencoded, or if you were just trying that to see if it solved your problem. If you do not want it, then your interface would look like this instead:
public interface DenningService {
#GET("/maps/api/geocode/json")
Single getEncodedRequest(#Query("key") String key,
#Query("latlng") String latlng);
}
This question already has answers here:
Get response status code using Retrofit 2.0 and RxJava
(3 answers)
Closed 5 years ago.
I used Retrofit with RxJava like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(HttpURL.BASE_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.client(okHttpClient)
.build();
and when the request error, such as password is wrong, the status code is 400, and the error msg will int the errorBoby to get me just like {code: 1000, message: "password is wrong"}.
However, the gons GsonConverterFactory will not fromJson in respone.getErrorBody , so I change my code just like this
Call<Result<User>> call = ApiManger.get().getLoginApi().login1(login);
call.enqueue(new Callback<Result<User>>() {
#Override
public void onResponse(Call<Result<User>> call, Response<Result<User>> response) {
if (response.code() == 0) {
mLoginView.onLoginSuccess(response.body().getData());
} else {
try {
Result result = new Gson().fromJson(response.errorBody().string(),Result.class);
ToastUtils.showShort(result.getMessage());
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Override
public void onFailure(Call<Result<User>> call, Throwable t) {
}
});
so it can not be used with Rxjava, how can I change it?
This can be done using Rx and here is how:
mSubscription.add(mDataManager.login(username, password)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Subscriber<User>() {
#Override
public void onCompleted() {
}
#Override
public void onError(Throwable e) {
if (NetworkUtil.isHttpStatusCode(e, 400) || NetworkUtil.isHttpStatusCode(e, 400)) {
ResponseBody body = ((HttpException) e).response().errorBody();
try {
getMvpView().onError(body.string());
} catch (IOException e1) {
Timber.e(e1.getMessage());
} finally {
if (body != null) {
body.close();
}
}
}
}
#Override
public void onNext(User user) {
//TODO Handle onNext
}
}));
}
NetworkUtil
public class NetworkUtil {
/**
* Returns true if the Throwable is an instance of RetrofitError with an
* http status code equals to the given one.
*/
public static boolean isHttpStatusCode(Throwable throwable, int statusCode) {
return throwable instanceof HttpException
&& ((HttpException) throwable).code() == statusCode;
}
}
You need to serialise the error body string first
try something like this in your onNext():
if (!response.isSuccessful()) {
JSONObject errorBody = new JSONObject(response.errorBody().string());
String message = errorBody.getString("message");
}
Its usually a better idea to accept the response in a standard format -
Class Response{
int code;
String message;
Data data; //////now data is the actual data that u need
/////getter setters
}
Now add an api method like this -
#GET("api_name")
Observable<Response> getResponse(Params);
now call retrofit.getResponse(params) and you will get the observable, subscribe to that observable and check its value in onNext and implement your logic. So in your case(password error) the data would be null, but you will have code and message.
I'm pretty new to RxJava and Retrofit and am trying to write my API calls with it. All the API calls return a JSON body on error which is in the general format as,
{"errors":[{"code":100, "message":"Login/Password not valid", "arguments":null}]}
Currently my code for the login API call (others are also similar) is,
mConnect.login(id, password)
.subscribe(new Subscriber<Token>() {
#Override
public void onCompleted() {
Log.d(TAG, "onCompleted()");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "onError(): " + e);
if (e instanceof HttpException) {
// dump e.response().errorBody()
}
}
#Override
public void onNext(Token token) {
Log.d(TAG, "onNext(): " + token);
}
});
When I get an error at the onError(), I would like to automatically decode the JSON in the error body to a POJO instead and use that. Is there a way to do this preferably in one place for all other API calls. Any help is appreciated.
I would suggest the use of a reusable Transformer along with the onErrorResumeNext operator to encapsulate your logic. It'd look something like this:
<T> Observable.Transformer<T, T> parseHttpErrors() {
return new Observable.Transformer<T, T>() {
#Override
public Observable<T> call(Observable<T> observable) {
return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
#Override
public Observable<? extends T> call(Throwable throwable) {
if (throwable instanceof HttpException) {
HttpErrorPojo errorPojo = // deserialize throwable.response().errorBody();
// Here you have two options, one is report this pojo back as error (onError() will be called),
return Observable.error(errorPojo); // in this case HttpErrorPojo would need to inherit from Throwable
// or report this pojo back as part of onNext()
return Observable.just(errorPojo); //in this case HttpErrorPojo would need to inherit from <T>
}
// if not the kind we're interested in, then just report the same error to onError()
return Observable.error(throwable);
}
});
}
};
}
Pay attention to the comments in the code, since you have to make the decision whether you want to report the parsed response onError() or onNext().
Then you can use this transformer anywhere in your API calls like this:
mConnect.login(id, password)
.compose(this.<Token>parseHttpErrors()) // <-- HERE
.subscribe(new Subscriber<Token>() {
#Override
public void onCompleted() {
Log.d(TAG, "onCompleted()");
}
#Override
public void onError(Throwable e) {
Log.e(TAG, "onError(): " + e);
if (e instanceof HttpErrorPojo) {
// this will be called if errorPojo was reported via Observable.error()
}
}
#Override
public void onNext(Token token) {
Log.d(TAG, "onNext(): " + token);
if (token instanceof HttpErrorPojo) {
// this will be called if errorPojo was reported via Observable.just()
}
}
});
Deserialize may be an issue too. You can use the retrofit converter to deserialize it (or do it yourself).
My solution adds a bit to the one from murki:
<T> Observable.Transformer<T, T> parseHttpErrors() {
return new Observable.Transformer<T, T>() {
#Override
public Observable<T> call(Observable<T> observable) {
return observable.onErrorResumeNext(new Func1<Throwable, Observable<? extends T>>() {
#Override
public Observable<? extends T> call(Throwable throwable) {
if ( throwable instanceof HttpException ) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(SERVER_URL) // write your url here
.addConverterFactory(GsonConverterFactory.create())
.build();
Converter<ResponseBody, Error> errorConverter =
retrofit.responseBodyConverter(Error.class, new Annotation[0]);
// Convert the error body into our Error type.
try {
Error error = errorConverter.convert(((HttpException) throwable).response().errorBody());
// Here you have two options, one is report this pojo back as error (onError() will be called),
return Observable.error(new Throwable(error.getMessage()));
}
catch (Exception e2) {
return Observable.error(new Throwable());
}
}
// if not the kind we're interested in, then just report the same error to onError()
return Observable.error(throwable);
}
});
}
};
}
and then at the onError(),
#Override
public void onError(Throwable e) {
progressBar.setVisibility(View.GONE); // optional
if ( !TextUtils.isEmpty(e.getMessage()) ) {
// show error as you like
return;
}
// show a default error if you wish
}