Как прописать глобальный преобразователь ошибок на retrofit 2+rx-android?

Мой сервер возвращает объекты Java домена, когда все идет хорошо, но возвращает объект ErrorResponse, когда возникает ошибка. (EDIT: сервер возвращает http-код 40x и тело json с информацией об ошибке). Как я могу зарегистрировать глобальный преобразователь ошибок на модификации 2 + rx-android, чтобы не делать одно и то же при каждом отдельном вызове?

В настоящее время я делаю это так при каждом вызове:

MyApiRx.doSomething(params)
  .subscribeOn(Schedulers.io())
  .subscribe(response -> responseHandler(),
             throwable -> {
               HttpException err = (HttpException) throwable;
               Converter<ResponseBody, ErrorResponse> ec = retrofit.responseConverter(ErrorResponse.class, new Annotation[]{});
               ErrorResponse errorResponse =  ec.convert(err.response().errorBody());
             });

Может быть, мне следует написать собственный CallAdapterFactory, который обработает это автоматически и вернет Observable с onError (ErrorResponse err) вместо стандартного onError (Throwable t)?

Любые идеи о том, как этого добиться?

Это хорошая идея?


person pakman    schedule 19.01.2016    source источник
comment
ознакомьтесь с этой сутью gist.github.com/rahulgautam/25c72ffcac70dacb87bd и этой проблемой github github.com/square/retrofit/issues/1102   -  person LordRaydenMK    schedule 20.01.2016


Ответы (1)


Есть несколько интересных методов Observable, которые вы могли бы использовать. Особенно вы должны взглянуть на эти два:

onErrorResumeNext(Func1<Throwable, Observable> resumeFunction)

doOnError(Action1<Throwable> onError)

И так как я не вижу (в вашем примере) необходимости в еще одном Observable для получения контроля над потоком, последний, вероятно, будет для вас лучше.

Что вы могли бы сделать, так это создать класс, который будет обертывать обработчик ваших ошибок (например, вот так):

public static class Response {
    private static final Action1<Throwable> ERROR_HANDLER = new Action1<Throwable>() {
        @Override
        public void call(Throwable throwable) {
            HttpException err = (HttpException) throwable;
            Converter<ResponseBody, ErrorResponse> ec = retrofit.responseConverter(ErrorResponse.class, new Annotation[]{});
            ErrorResponse errorResponse =  ec.convert(err.response().errorBody());
        }
    };

    public static Action1<Throwable> handleError() {
        return ERROR_HANDLER;
    }
}

А затем вызовите свой API с помощью:

MyApiRx.doSomething(params)
  .subscribeOn(Schedulers.io())
  .doOnError(Response.handleError())
  .subscribe(response -> responseHandler());
person Bartek Lipinski    schedule 20.01.2016
comment
Спасибо за предложение. Я попробую это. Однако с этим подходом я вижу две проблемы: 1. Предлагаемый вами класс/методы не могут быть статическими, поскольку они требуют экземпляра модификации. 2. Мне все еще приходится .doOnError по каждому запросу. - person pakman; 25.01.2016
comment
Что касается первой проблемы - она ​​все еще может быть статической, ее просто нужно инициализировать, как только вы получите свой экземпляр Retrofit. Если вы используете какой-то фреймворк для внедрения зависимостей (например, кинжал), это будет особенно просто. Что касается последнего вопроса: вам придется что-то делать. Если вам не нравится doOnError, вы можете использовать вместо него compose (вот хорошая статья Дэна Лью об этой функции, если вам нужна ссылка). - person Bartek Lipinski; 25.01.2016