RxJava 线性退避,在重试时传递较早的日期参数

RxJava linear backoff, passing in earlier date parameters on retry

我正在重构一些代码,这些代码会调用带有格式化日期参数(例如“2016-3-10”)的 Web 服务,如果返回 null,有一天会触发另一个带有日期的方法更早(如“2016-3-9”)。这将至少重试 3 次。

我正在将其重构到 RxJava 中,但不确定如何实施退避策略或在这种情况下使用哪个 .retry().retryWhen() 运算符。

我使用 Retrofit 让 Web 服务返回通常的 Observable

这是我目前拥有的:

 PictureService pictureService = retrofit.create(PictureService.class);

        pictureService.getPhotos(date)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .retry() //Some retry

                ...
                .subscribe()

那么这里最好使用哪个运算符来重试请求,当当前日期 returns 为空时,我应该如何将新日期传递给 getPhotos() 请求?

为了完成这里是上面提到的 Retrofit 服务:

@GET("/someurl/photos?api_key=xxxxxxx")
Observable<PictureAPI> getPhotos(@Query("earth_date") String earthDate);

好的,现在我可以再次回答这个问题了,我们开始吧:

Observable.just("2016-3-10", "2016-3-9", "2016-3-8")
.concatMap(date -> pictureService.getPhotos(date))
.filter(response -> response != null)
.take(1)...

有关详细说明,请查看 Dan Lew 的博客 post:http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/

简而言之:concat(和 concatMap)将订阅每个新的 Observable 只有在前一个发出 onCompleted 并且仅当需要更多项目时下游。 take(1) 将在第一个非 null 响应后取消订阅,因此 concatMap 将不会订阅下一个 Observable.

编辑: 要检查是否真的只发送了一个请求,您可以

1.) 在 Retrofit 中启用日志记录(如果您是最新版本,请在 OkHttpClient 中添加 Interceptor)。这使您可以直接观察正在发送的请求。

2.) 添加一个 doOnSubscribe() 像这样:

.concatMap(date -> pictureService.getPhotos(date)
    .doOnSubscribe(new Action0() {
        @Override
        public void call() {
            Log.d(TAG, "sending request for " + date);   
        }
    });
)

由于 Retrofit 请求仅在订阅时发送,当且仅当随后发送请求时,日志消息才会出现。