I'm calling an API using Retrofit 2 and RxJava2. If a call fails, in some cases (e.g. no Internet connection), I want to display an error dialog to the user and let him retry.
As I'm using RxJava, I was thinking of using .retryWhen(...)
but I don't know how to do that as it needs to wait for the user to press the button on the dialog.
At the moment I display the dialog but it retries before the user presses any button. Plus I would like the call to not be retried when the user presses 'cancel'.
Here is the code I have at the moment:
private void displayDialog(DialogInterface.OnClickListener positive, DialogInterface.OnClickListener negative) {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("Unexpected error, do you want to retry?")
.setPositiveButton("Retry", positive)
.setNegativeButton("Cancel", negative)
.show();
}
private Observable<Boolean> notifyUser() {
final PublishSubject<Boolean> subject = PublishSubject.create();
displayDialog(
(dialogInterface, i) -> subject.onNext(true),
(dialogInterface, i) -> subject.onNext(false)
);
return subject;
}
private void onClick() {
Log.d(TAG, "onClick");
getData()
.observeOn(AndroidSchedulers.mainThread())
.subscribeOn(Schedulers.io())
.retryWhen(attempts -> {
return attempts.zipWith(
notifyUser(),
(throwable, res) -> res);
})
.subscribe(
s -> {
Log.d(TAG, "success");
});
}
final PublishSubject<Object> retrySubject = PublishSubject.create();
disposable.add(getData()
.doOnError(throwable -> enableButton())
.retryWhen(observable -> observable.zipWith(retrySubject, (o, o2) -> o))
.subscribeWith(/* do what you want with the result*/)
}));
When button is clicked you trigger this event:
retrySubject.onNext(new Object());
As you can see in this Marble diagram:
the error is not propagated. The retryWhen
operator will indeed handle it and do a proper action. This is the reason why you have to enable (or for example show a Dialog) in doOnError
, before retryWhen
operator.
When you don't want to listen anymore for successive retry attempts, you just need to unsubscribe:
disposable.dispose();
As per your question:
What should I do if I want to retry only on a specific Exception but not on the other ones?
You can modify your retryWhen
in this way:
.retryWhen(throwableObservable -> throwableObservable.flatMap(throwable -> {
if (throwable instanceof TargetException) {
return Observable.just(throwable).zipWith(retrySubject, (o, o2) -> o);
} else {
throw Throwables.propagate(throwable);
}
}))
Where Throwables.propagate(throwable)
is a Guava util that can be replaced with throw new RuntimeException(throwable);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With