用RxJava处理分页

我在Android应用程序上使用Retrofit + RxJava,并且询问自己如何处理API分页来链接调用,直到检索到所有数据。 是这样的:

Observable<ApiResponse> getResults(@Query("page") int page); 

ApiResponse对象具有简单的结构:

 class ApiResponse { int current; Integer next; List<ResponseObject> results; } 

该API将返回下一个值,直到最后一页。

有一些很好的方法来实现这一目标? 试图结合一些flatMaps() ,但没有成功。

你可以recursion地build模:

 Observable<ApiResponse> getPageAndNext(int page) { return getResults(page) .concatMap(new Func1<ApiResponse, Observable<ApiResponse>>() { @Override public Observable<ApiResponse> call(ApiResponse response) { // Terminal case. if (response.next == null) { return Observable.just(response); } return Observable.just(response) .concatWith(getPageAndNext(response.next)); } }); } 

那么,要消耗它,

 getPageAndNext(0) .concatMap(new Func1<ApiResponse, Observable<ResponseObject>>() { @Override public Observable<ResponseObject> call(ApiResponse response) { return Observable.from(response.results); } }) .subscribe(new Action1<ResponseObject>() { /** Do something with it */ }); 

这应该得到一个ResponseObject的stream,将按顺序到达,最有可能到达页面大小的块。

我在类似的post中回答了我的解决scheme: https : //stackoverflow.com/a/34378263/143733

@Iopar提供的解决scheme的技巧或修正是包含一个可以通过各种方式发出的“触发器”Observable。

在我发布的代码中,一旦处理了整个页面的元素,它就会被发射,但是也可能发生在用户单击button/滚动的基础上。

Iopar举了一个很好的例子。

只是一个小的补充。
如果您想在onNext()调用中获取所有页面。
当你想用一个更多的Observable 压缩这个结果时,这会很有帮助。
你应该写:

 private List<String> list = new LinkedList() { { add("a"); add("b"); add("c"); } }; int count = 1; public Observable<List<String>> getAllStrings(int c) { return Observable.just(list) .concatMap( strings -> { if (c == 3) { return Observable.just(list); } else { count += 1; return Observable.zip( Observable.just(list), getAllStrings(count), (strings1, strings2) -> { strings1.addAll(strings2); return strings1; } ); } } ); } 

用法

 getAllStrings(0) .subscribe(strings -> { Log.w(TAG, "call: " + strings); }); 

你会得到:

 call: [a, b, c, a, b, c, a, b, c, a, b, c]