显示对话框后,使用Retrofit 2和RxJava2重试呼叫 [英] Retry a call with Retrofit 2 and RxJava2 after displaying a dialog

查看:116
本文介绍了显示对话框后,使用Retrofit 2和RxJava2重试呼叫的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用Retrofit 2和RxJava2调用API.如果在某些情况下(例如没有Internet连接)通话失败,我想向用户显示错误对话框,然后让他重试.

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.

当我使用RxJava时,我正在考虑使用 .retryWhen(...),但是我不知道该怎么做,因为它需要等待用户按下对话框上的按钮.

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'.

这是我目前的代码:

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:

错误不会传播. retryWhen 运算符确实会处理它并采取适当的措施.这就是为什么必须在 retryWhen 运算符之前在 doOnError 中启用(或显示对话框)的原因.

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();

根据您的问题:

如果我只想重试特定异常但应该怎么办?不是其他人吗?

What should I do if I want to retry only on a specific Exception but not on the other ones?

您可以通过以下方式修改 retryWhen :

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);
      }
}))

其中 Throwables.propagate(throwable)是一个Guava实用程序,可以替换为 throw new RuntimeException(throwable);

Where Throwables.propagate(throwable) is a Guava util that can be replaced with throw new RuntimeException(throwable);

这篇关于显示对话框后,使用Retrofit 2和RxJava2重试呼叫的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆