本文介绍了Retrofit 2和RxJava错误处理运算符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的项目中使用带有Observable界面和Result包装器的Retrofit 2.示例:

I'm using Retrofit 2 in my project with Observable interface and the Result wrapper. Example:

@POST("api/login")
Observable<Result<LoginResponse>> login(@Body LoginRequest request);

我需要结果包装器从响应中获得的信息不仅仅是序列化的对象(例如标头,http状态...).

I need the Result wrapper to obtain more information from the response than just the serialized object (for example headers, http status...).

问题是,使用结果"包装器,网络调用不会引发任何异常.您可以通过调用Result.error()在结果内部找到异常.

Problem is, with the Result wrapper no exception is thrown by the network call. You can find the exception inside the result by calling Result.error().

如果我想利用RxJava错误运算符怎么办?例如,我想在发生网络错误时使用重试运算符,但是重试运算符仅在可观察对象抛出异常的情况下才有效.

What should I do if I want to take advantage of RxJava error operators?For example, I'd like to use the retry operator on a network error, but the retry operator only works if an exception is thrown by the observable.

推荐答案

这是我想出的解决方案.如果我要改善它,我会在此处发布更改.

Here is the solution I came up with.If I will improve it I will post the changes here.

我的问题的解决方案(由Retrofit吞噬且未由RxJava处理的异常)是 Observable.error 方法,该方法创建一个仅发出错误的新observable,因此我可以抛出"

The solution to my problem (exception swallowed by Retrofit and not handled by RxJava) is the Observable.error method that creates a new observable that only emits the error, so I can "rethrow" the exception.

我创建了一个可观察的转换器,将其附加到发出了Retrofit.Result的每个rest调用之后.该转换器采用Observable>,如果响应没有错误,则将其转换为Observable>.如果有错误,它将返回带有自定义Http * Exceptions的Observable.error,以后可以在onError回调中的Observer中处理.我将其作为名为 ObservableTransformations.resultToResponseWithHttpErrorHandling 的实用工具类的静态方法.

I created an observable transformer to append to every rest call that emits a retrofit.Result.This transformer takes an Observable> and, if the response has no errors, transforms it into an Observable>. If there are errors it returns an Observable.error with custom Http*Exceptions that I can later handle in my Observer in the onError callback.I put it as a static method of an utility class called ObservableTransformations.resultToResponseWithHttpErrorHandling.

这里是:

public class ObservableTransformations {

public static <T> Observable.Transformer<Result<T>, Response<T>> resultToResponseWithHttpErrorHandling() {
    return observable -> observable.flatMap(r -> {
        Observable<Response<T>> returnObservable = Observable.just(r.response());
        if (r.isError()) {
            Throwable throwable = r.error();
            if (throwable instanceof IOException) {
                Timber.e(throwable, "Retrofit connection error.");
                // TODO Check this cases
                if (throwable instanceof java.net.ConnectException) {
                    returnObservable = Observable.error(new HttpNoInternetConnectionException());
                } else if (throwable instanceof SocketTimeoutException) {
                    returnObservable = Observable.error(new HttpServerDownException());
                } else {
                    returnObservable = Observable.error(new HttpNoInternetConnectionException());
                }
            } else {
                Timber.e(throwable, "Retrofit general error - fatal.");
                returnObservable = Observable.error(new HttpGeneralErrorException(r.error()));
            }
        } else {
            Response<T> retrofitResponse = r.response();
            if (!retrofitResponse.isSuccess()) {
                int code = retrofitResponse.code();
                String message = "";
                try {
                    message = retrofitResponse.errorBody().string();
                } catch (IOException e) {
                    Timber.e(e, "Error reading errorBody from response");
                }
                Timber.i("Server responded with error. Code: " + code + " message: " + message);
                Throwable t = null;
                if (NetworkUtils.isClientError(code)) {
                    t = new HttpClientException(retrofitResponse.code(), message);
                } else if (NetworkUtils.isServerError(code)) {
                    t = new HttpServerErrorException(retrofitResponse.code(), message);
                }
                returnObservable = Observable.error(t);
            }
        }
        return returnObservable;
    }).retryWhen(new RetryWithDelayIf(3, 1000, t -> {
        return (t instanceof HttpNoInternetConnectionException) || (t instanceof HttpServerDownException);
    }));
}

}

仅当异常为HttpNoInternetConnectionException或HttpServerDownException时,才使用指数补偿进行3次重试.

The retry is made 3 times using an exponential backoff, and only if the exception is HttpNoInternetConnectionException or HttpServerDownException.

RetryWithDelayIf 类在这里.重试将满足重试条件的条件作为构造函数的最后一个参数(一个函数采用throwable,如果此throwable应该触发重试,则返回true,否则返回false).

The RetryWithDelayIf class is here. It takes the condition to be met for retry as the last argument of the constructor (a function taking a throwable and returning true if this throwable should trigger the retry and false if not).

public class RetryWithDelayIf implements
    Func1<Observable<? extends Throwable>, Observable<?>> {

private final int maxRetries;
private final int retryDelayMillis;
private int retryCount;
private Func1<Throwable, Boolean> retryIf;

public RetryWithDelayIf(final int maxRetries, final int retryDelayMillis, Func1<Throwable, Boolean> retryIf) {
    this.maxRetries = maxRetries;
    this.retryDelayMillis = retryDelayMillis;
    this.retryCount = 0;
    this.retryIf = retryIf;
}

@Override
public Observable<?> call(Observable<? extends Throwable> attempts) {
    return attempts.zipWith(Observable.range(1, maxRetries + 1), (n, i) -> {
        return new Tuple<Throwable, Integer>(n, i);
    })
            .flatMap(
                    ni -> {
                        if (retryIf.call(ni.getFirst()) && ni.getSecond() <= maxRetries) {
                            return Observable.timer((long) Math.pow(2, ni.getSecond()), TimeUnit.SECONDS);
                        } else {
                            return Observable.error(ni.getFirst());
                        }
                    });
}

}

最后,这是restService调用的用法:

Finally, here is the usage with a restService call:

restService.login(new LoginRestRequest(username, password))
                .compose(ObservableTransformations.resultToResponseWithHttpErrorHandling());

在观察者的 onError 中,您终于可以处理Http * Exceptions.

In the onError of your observer you can finally handle the Http*Exceptions.

这篇关于Retrofit 2和RxJava错误处理运算符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-16 00:48