什么是通过过滤序列获得最后未过滤结果的惯用方法?

时间:2018-01-29 10:35:15

标签: rx-java

我必须连续几次调用一个外部API方法,直到我要么用完了尝试,要么得到肯定的回复。如果我没有尝试,我仍然希望使用(用于记录/诊断目的)最新的不成功响应。目前我这样做:

        class SimpleWrapper<T> {
        private T data;

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }
    }

    SimpleWrapper<String> state = new SimpleWrapper<>();

    Observable<Response> getLogObservable = Observable.interval(checkInterval, TimeUnit.SECONDS)
            .take(checkCount)
            .flatMap(ignored -> api.check())
            .doOnNext(response -> {
                logger.info("Check response: {}", response.getMessage());
                state.setData(response.getMessage());
            })
            .firstOrDefault(null, HubLogsApiResponse::isSuccess)
            .flatMap(response -> {
                if (response == null) {
                    return Observable.error(new RuntimeException(String.format("Last call to check was unsuccessful: %s", state.getData())));
                } else {
                    return Observable.just(response);
                }
            })

这很丑,需要我使用副作用,但我不知道如何才能实现这一点。

有任何建议吗?

1 个答案:

答案 0 :(得分:0)

问题:发出一系列请求,并返回第一个成功请求,或者返回最后一个请求。

如果我们引入Pair,我们可以将interval生成的计数与API请求结合起来。然后,可以在不设置全局变量的情况下检查终止条件。

Observable<Response> getLogObservable = 
  Observable.interval(checkInterval, TimeUnit.SECONDS)
        .flatMap(requestNumber -> api.check()
                                    .map(response -> 
                                         new Pair(requestNumber+1, response))
        .flatMap(pair -> mapResponse( pair ) )
        .take( 1 );

Observable<Response> mapResponse( Pair<Long, Response> response ) {
  if ( response.getSecond().isSuccess() ) {
    return Observable.just( response.getSecond() );
  }
  if ( response.getFirst() >= checkCount ) {
    Observable.error(
      new RuntimeException(String.format("Last call to check was unsuccessful: %s", 
            pair.getSecond().getData())));
  }
  return Observable.empty();
}

mapResponse只会在计数器运行过程中产生包含最新响应的错误。否则,它返回成功的响应或空的observable。