android - 在显示对话框后重试使用 Retrofit 2 和 RxJava2 的调用

标签 android rx-java2 retrywhen

我正在使用 Retrofit 2 和 RxJava2 调用 API。 如果调用失败,在某些情况下(例如没有互联网连接),我想向用户显示一个错误对话框并让他重试。

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

此时我显示对话框,但它会在用户按下任何按钮之前重试。另外,我希望在用户按下“取消”时不重试调用。

这是我目前的代码:

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

单击按钮时触发此事件:

retrySubject.onNext(new Object());

正如您在此 Marble 图中所见:

enter image description here

错误不会传播。 retryWhen 运算符确实会处理它并执行适当的操作。这就是为什么您必须在 retryWhen 运算符之前在 doOnError 中启用(或例如显示对话框)的原因。

当您不想再收听连续的重试尝试时,您只需取消订阅:

disposable.dispose();

根据您的问题:

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

你可以这样修改你的retryWhen:

.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 util,可以替换为 throw new RuntimeException(throwable);

关于android - 在显示对话框后重试使用 Retrofit 2 和 RxJava2 的调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47672224/

相关文章:

javascript - Phonegap 上传带标题的图片并检索它们

node.js - 在重试时设置动态延迟

java - Spring WebClient - 如何根据响应头延迟重试

java - 当我想在 ArrayList 中添加来自请求 json 的对象时

JavascriptInterface 函数导致网页上的 javascript 崩溃

android - 是否可以通过嵌入式 iframe 将 Android 应用程序的域设置为白名单?

java - RxJava 中的 Zip 运算符不适用于 Retrofit

java - RxJava2 从监听器创建 Flowable 并在最后删除监听器

android - 什么时候在 ViewModel 中处理 RxJava2 Disposable?