我正在Android应用上使用Retrofit + RxJava,并且问自己如何处理链接调用的API分页,直到检索到所有数据。是这样的:
Observable<ApiResponse> getResults(@Query("page") int page);
ApiResponse 对象具有简单的结构:
class ApiResponse {
int current;
Integer next;
List<ResponseObject> results;
}
API会返回下一个值,直到最后一页为止。
有一些很好的方法来实现这一目标吗?试图结合一些 flatMaps(),但没有成功。
答案 0 :(得分:53)
你可以递归地建模:
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
的流,它将按顺序到达,并且很可能以页面大小的形式到达。
答案 1 :(得分:3)
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]