Skip to content

Instantly share code, notes, and snippets.

@vipulshah2010
Created June 6, 2016 05:39
Show Gist options
  • Save vipulshah2010/2178a46bbed3d7bf9ce2334c02079a36 to your computer and use it in GitHub Desktop.
Save vipulshah2010/2178a46bbed3d7bf9ce2334c02079a36 to your computer and use it in GitHub Desktop.
RxAndroid Error Handling
public class RetrofitException extends RuntimeException {
public static RetrofitException httpError(String url, Response response, Retrofit retrofit) {
String message = response.code() + " " + response.message();
return new RetrofitException(message, url, response, Kind.HTTP, null, retrofit);
}
public static RetrofitException networkError(IOException exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.NETWORK, exception, null);
}
public static RetrofitException unexpectedError(Throwable exception) {
return new RetrofitException(exception.getMessage(), null, null, Kind.UNEXPECTED, exception, null);
}
/** Identifies the event kind which triggered a {@link RetrofitException}. */
public enum Kind {
/** An {@link IOException} occurred while communicating to the server. */
NETWORK,
/** A non-200 HTTP status code was received from the server. */
HTTP,
/**
* An internal error occurred while attempting to execute a request. It is best practice to
* re-throw this exception so your application crashes.
*/
UNEXPECTED
}
private final String url;
private final Response response;
private final Kind kind;
private final Retrofit retrofit;
RetrofitException(String message, String url, Response response, Kind kind, Throwable exception, Retrofit retrofit) {
super(message, exception);
this.url = url;
this.response = response;
this.kind = kind;
this.retrofit = retrofit;
}
/** The request URL which produced the error. */
public String getUrl() {
return url;
}
/** Response object containing status code, headers, body, etc. */
public Response getResponse() {
return response;
}
/** The event kind which triggered this error. */
public Kind getKind() {
return kind;
}
/** The Retrofit this request was executed on */
public Retrofit getRetrofit() {
return retrofit;
}
/**
* HTTP response body converted to specified {@code type}. {@code null} if there is no
* response.
*
* @throws IOException if unable to convert the body to the specified {@code type}.
*/
public <T> T getErrorBodyAs(Class<T> type) throws IOException {
if (response == null || response.errorBody() == null) {
return null;
}
Converter<ResponseBody, T> converter = retrofit.responseBodyConverter(type, new Annotation[0]);
return converter.convert(response.errorBody());
}
}
public class RxErrorHandlingCallAdapterFactory extends CallAdapter.Factory {
private final RxJavaCallAdapterFactory original;
private RxErrorHandlingCallAdapterFactory() {
original = RxJavaCallAdapterFactory.create();
}
public static CallAdapter.Factory create() {
return new RxErrorHandlingCallAdapterFactory();
}
@Override
public CallAdapter<?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
return new RxCallAdapterWrapper(retrofit, original.get(returnType, annotations, retrofit));
}
private static 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(Call<R> call) {
return ((Observable) wrapped.adapt(call)).onErrorResumeNext(new Func1<Throwable, Observable>() {
@Override
public Observable call(Throwable throwable) {
return Observable.error(asRetrofitException(throwable));
}
});
}
private RetrofitException asRetrofitException(Throwable throwable) {
// We had non-200 http error
if (throwable instanceof HttpException) {
HttpException httpException = (HttpException) throwable;
Response response = httpException.response();
return RetrofitException.httpError(response.raw().request().url().toString(), response, retrofit);
}
// A network error happened
if (throwable instanceof IOException) {
return RetrofitException.networkError((IOException) throwable);
}
// We don't know what happened. We need to simply convert to an unknown error
return RetrofitException.unexpectedError(throwable);
}
}
}
@vipulshah2010
Copy link
Author

Usages

subscription = RestApiBuilder
                .getBooksProvider()
                .getBooks()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .map(new Func1<Books, String>() {
                    @Override
                    public String call(Books books) {
                        return null;
                    }
                })
                .subscribe(new Subscriber<String>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        RetrofitException error = (RetrofitException) e;
                    }

                    @Override
                    public void onNext(String s) {

                    }
                });

@BlackMin
Copy link

Hi, thank you for this gist!
I use this gist in my project, when the web request returns connect refused by the server, a crash happened, have you ever met it?
Below is the crash log:
java.lang.IllegalStateException: Expected BEGIN_OBJECT but was STRING at line 1 column 1 path at line 56,at line 21,at 37 at 34....

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment