Oto rozwiązanie, które wymyśliłem. Jeśli to poprawię, opublikuję zmiany tutaj.
Rozwiązanie mojego problemu (wyjątek połkniętego przez Retrofit i nie obsługiwane przez RxJava) jest metoda Observable.error że tworzy nowy zaobserwować, że tylko emituje ten błąd, więc mogę „przekaż” wyjątek.
Stworzyłem obserwowalny transformator, który będzie dołączany do każdego połączenia, które wyemituje doposażenie.Wyniki. Ten transformator przyjmuje obserwowalne> i, jeśli odpowiedź nie zawiera błędów, przekształca go w Obserwowalne>. Jeśli występują błędy, zwraca obiekt Observable.error z niestandardowymi wyjątkami Http *, które mogę później obsłużyć w moim obserwatorze w wywołaniu zwrotnym onError. Ustanawiam to jako statyczną metodę klasy narzędziowej o nazwie ObservableTransformations.resultToResponseWithHttpErrorHandling.
Tutaj jest on:
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);
}));
}
}
Ponowna próba jest 3 razy przy użyciu odczekiwanie wykładniczym, a tylko wtedy, gdy wyjątek HttpNoInternetConnectionException lub HttpServerDownException.
Klasa RetryWithDelayIf jest tutaj. Warunek jest spełniony, aby ponowić próbę, jako ostatni argument konstruktora (funkcja pobierająca i zwracającą wartość true, jeśli ta opcja powinna wywołać ponowną próbę i wartość false, jeśli nie).
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());
}
});
}
}
Wreszcie, tutaj jest wykorzystanie z rozmowy restService:
restService.login(new LoginRestRequest(username, password))
.compose(ObservableTransformations.resultToResponseWithHttpErrorHandling());
W onError swojego obserwatora można wreszcie obsługiwać HTTP * Wyjątki.
Zobacz link http://bytes.babbel.com/pl/artykuly/2016-03-16-retrofit2-rxjava-error-handling.html Opisują one, jak nadpisać _RxJavaCallAdapterFactory_ w _Retrofit.Builder_ i tam dla możesz łapać swoje obiekty w _Observable.onResumeErrorNext_/_Observable.onDoNext() _ – murt