重复调用API,直到整个数据被下载数据

时间:2015-05-22 07:51:56

标签: java rx-java

我有一个用例,我想反复为每个用户调用一个Web API,直到下载完整个数据。

我拥有的Web API允许每个API请求为用户提取最多100条记录。我可以指定要为该用户下载的记录的startTime和结束时间戳:

void downloadRecord(String userId, recordStartTime, recordEndTime, int countOfRecord, ResultCallBack)

如果recordStartTimerecordEndTime之间的记录数超过100,则API响应仅返回100条记录。然后我必须通过新的开始时间(刚刚下载的第100条记录的时间)循环调用此api,直到下载所有记录。

final long recordStartTime = timeStampFrom2DaysAgo//;
Observable.from(arrayListOfUserIds).flatMap(new Func1<String, Observable<?>>() {
    @Override
    public Observable<?> call(String userId) {
        long recordEndTime = getCurrentTimeMS();
        //keep downloading records 
        downloadRecord(userId, recordStartTime, recordEndTime, 100, new ResultCallBack() {
            //if records are < 100 then stop 
            //else keep downloading 
        });
    }
}).subscribe();

请建议我是否有可用于解决问题的RxJava示例代码。

由于

2 个答案:

答案 0 :(得分:4)

这是一个循环相关的Observables。想象一下,你有一个Observable用于请求,一个Observable用于响应。 requests Observable发出一些DownloadParams个对象,包含userId,recordStartTime,recordEndTime和countOfRecord,因此Observable<DownloadParams> requestsresponses Observable会发出记录列表,即Observable<List<Record>> responses

responses显然取决于requests,但不那么明显的部分是我们还需要requests依赖responses,因为下次从服务器下载,某些DownloadParams取决于我们从之前的下载中获得的响应。为了完整性,requests实际上还取决于一些初始化Observable,它发出userId来执行第一次下载。您可以使用.startWith(firstDownloadParams)替换此初始化Observable。

无论如何,困难的部分是表达循环依赖。好消息是这在Rx中是可能的,并且已经the focus of Cycle.js framework based on RxJS。坏消息是,如果没有主题,我们就无法解决这个问题,这可能是不可取的。

最好让RxJava代码保持尽可能的功能,但通过尝试这样做我们就会遇到问题。如果我们尝试将Observable声明为其他人的函数,我们得到:

Observable<DownloadParams> requests = responses.flatMap( /* ... */ )
    .startWith(firstDownloadParams);
Observable<List<Record>> responses = requests.flatMap( /* ... */ );

这不会编译,因为第一个声明需要第二个声明,反之亦然。这是受试者可以提供的帮助。我们将其中一个Observable声明为主题:

PublishSubject<List<Record>> responsesProxy = PublishSubject.create();
Observable<DownloadParams> requests = responsesProxy.flatMap( /* ... */ )
    .startWith(firstDownloadParams);
Observable<List<Record>> responses = requests.flatMap( /* ... */ );

主题responsesProxy将充当responses的代理,以便我们能够根据requests声明responsesProxy。但现在我们需要responsesProxy来模仿responses。我们通过添加以下内容来实现:

responses.subscribe(responsesProxy);

这会关闭循环依赖中的循环,但只记得在我们上面的订阅之后也正确处理了主题。

现在我们只需填写那些flatMap中的转换。在requests.flatMap( )中,您应该执行下载记录列表的网络调用。您可能希望将其作为Observable处理,而不是作为回调处理,以简化与其余RxJava代码的相互作用。

responsesProxy.flatMap( )中,您应该检查记录列表是否为100或更多,并使用新的recordStartTime创建下一个DownloadParams,并将其包装为Observable.just(newDownloadParams)。如果小于100,则返回Observable.empty()

答案 1 :(得分:2)

这可能会变得复杂:请参阅示例gist here

基本上你需要踩踏有关后续查询时间窗口的请求。请注意,BufferUntilSubscriber是内部的,但RxJava没有任何正式的Subject变体,它会在订阅发生之前缓存值,然后丢弃缓存。

修改:更新了要点,因此它不会触发MissinBackpressureException