基于逻辑的 RxJava 重试

9
这是一个案例,我使用Retrofit进行API调用,可能由于网络错误而失败。如果失败,我们将显示一个带有重试按钮的错误消息。当用户按下重试按钮时,我们需要重新尝试最新的Observable。
可能的解决方案:
  1. 重试:应在订阅可观察对象之前使用重试,如果发生错误,它将立即再次订阅,这不是我想要的,我只需要在用户按下重试按钮后重新订阅。

  2. RetryWhen:在发出项目并继续发出项目直到发出Observable错误时,它将一直尝试。这里也存在同样的问题,除非用户决定开始重试过程,否则我不需要启动重试过程。

  3. 重新订阅相同的Observable:此解决方案将开始发出Observable项,但我们正在使用缓存运算符,因此如果一个Observable失败,我们将缓存失败的项,当我们再次订阅时,我们将再次得到相同的错误。

还有其他解决方案吗?
1个回答

8
您可以使用retryWhen方法,其中参数Func1返回一个Observable,该Observable指示何时应进行重试。例如:
PublishSubject<Object> retryButtonClicked = PublishSubject.create();

Observable
        .error(new RuntimeException())
        .doOnError(throwable -> System.out.println("error"))
        .retryWhen(observable -> observable.zipWith(retryButtonClicked, (o, o2) -> o))
        .subscribe();

retryButtonClicked.onNext(new Object());

每次retryButtonClicked触发一个事件时,Observable都会重新尝试。
这里还有一个例子- https://gist.github.com/benjchristensen/3363d420607f03307dd0

没有任何重试发生,我认为retryWhen并不像你所解释的那样工作,第一次retryWhen调用zipWith时,由于用户尚未点击按钮而未收到发出的项目,它将放弃重试并吞噬错误。 - Mahdi Hijazi
retryWhen 在错误发生时不会被调用,它只会在可观测对象创建时被调用一次,并返回一个 Observable,指示何时重试。我以上发布的代码会打印两次 "error"。 - krp
谢谢,你的解决方案有效了,是我在将其应用到我的代码中时犯了错误。请问您能否解释一下或指出任何有用的内容,说明为什么我不应该使用订阅者(subscriber),而应该使用doOnNext、doOnError呢? - Mahdi Hijazi
为澄清起见。使用带有cache(retryWhen(操作符,您可以强制清除缓存吗? - Blundell
@krp 如果没有网络,我希望在用户点击重试按钮时重新连接。你的答案对我不起作用。我正在使用具有Retrofit的单个可观察对象。 - Taha Sami

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接