RxJava заставляет retryWhen() запускать метод onError()
У меня есть следующий класс с реализацией RxJava для загрузки двух ресурсов из API. Я делаю некоторые rx, чтобы позволить ему повторить или повторить, если он не отвечает требованиям API / соединения. Тем не менее, я не могу заставить retryWhen() запускать onError() после попытки более 3 раз.
ВОПРОС / ПОМОЩЬ
пожалуйста, просмотрите мой код и помогите мне решить эту проблему.
НОТА
Я реализую Rx, прочитав эти две статьи. статья 1, статья 2
SplashPresenter.class
public class SplashPresenter implements SplashContract.Presenter {
private static final String TAG = SplashPresenter.class.getName();
private static final int RETRY_TIMEOUT = 10;
private static final int STOP_RETRY_TIME = 3;
private static final int START_RETRY_TIME = 1;
private SplashContract.View mView;
@Override
public void init(SplashContract.View view) {
this.mView = view;
}
@Override
public void onResume() {
GetRemoteReceiverRelationshipSpec relationSpec = new GetRemoteReceiverRelationshipSpec();
GetRemoteIncompleteReasonSpec reasonSpec = new GetRemoteIncompleteReasonSpec();
Observable<RepoResult<ArrayList<IncompleteReasonViewModel>>> queryReason =
Repository.getInstance().query(reasonSpec);
Repository.getInstance().query(relationSpec)
.concatMap(result -> queryReason)
.repeatWhen(complete -> complete
.zipWith(Observable.range(START_RETRY_TIME, STOP_RETRY_TIME), (v, i) -> i)
.flatMap(repeatCount -> {
Log.i(TAG, "Repeat attempt: " + repeatCount);
mView.showLoadingDialog();
return Observable.timer(RETRY_TIMEOUT,
TimeUnit.SECONDS);
}))
.takeUntil(RepoResult::isSuccess)
.retryWhen(error -> error
.zipWith(Observable.range(START_RETRY_TIME, STOP_RETRY_TIME), (v, i) -> i)
.flatMap(retryCount -> {
Log.i(TAG, "Retry attempt: " + retryCount);
mView.showLoadingDialog();
if (mView.getCommunicator() != null) {
mView.getCommunicator().onConnectionFail(retryCount);
}
return Observable.timer(RETRY_TIMEOUT,
TimeUnit.SECONDS);
}))
.filter(RepoResult::isSuccess)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
result -> Log.i(TAG, "onNext()"),
err -> {
Log.i(TAG, "onError()");
if (mView.getCommunicator() != null) {
mView.dismissLoadingDialog();
mView.getCommunicator().onSplashScreeDismissError();
}
},
() -> {
Log.i(TAG, "onComplete()");
if (mView.getCommunicator() != null) {
mView.dismissLoadingDialog();
mView.getCommunicator().onSplashScreenSuccessDismiss();
}
}
);
}
@Override
public void onPause() {
}
}
2 ответа
Когда я писал подобный код раньше, я бросил вручную Observable.error()
в flatMap
.flatMap(retryCount -> {
if (retryCount >= STOP_RETRY_TIME) {
return Observable.error(someException);
}
return Observable.timer(RETRY_TIMEOUT, TimeUnit.SECONDS);
}))
Чтобы сохранить бросаемый объект после повторной попытки (вместо создания пользовательского), возвращайте Observable с соответствующей ошибкой от оператора zipWith, когда retryCount превышает указанное ограничение.
.retryWhen(error -> {
Observable<Integer> range = Observable.range(START_RETRY_TIME, STOP_RETRY_TIME);
Observable<Observable<Long>> zipWith = error.zipWith(range, (e, i) ->
i < STOP_RETRY_TIME ?
Observable.timer(i, TimeUnit.SECONDS) :
Observable.error(e));
return Observable.merge(zipWith);
});
Передайте счетчик повторных попыток и ошибку в Pair
объект, если вы достигли предела повторных попыток, получите исключение от объекта пары и поднимите его.
source.retryWhen(errors -> errors
.zipWith(Observable.range(1, REQUEST_RETRY), Pair::new)
.flatMap(errPair -> {
int retryTime = errPair.second;
if (retryTime < REQUEST_RETRY) {
return Observable.timer(retryTime * RETRY_DELAY, TimeUnit.MILLISECONDS);
} else {
return Observable.error(errPair.first);
}
})
.doOnError(this::handleError));