使用 RxJava 处理分页
Posted
技术标签:
【中文标题】使用 RxJava 处理分页【英文标题】:Handle Paging with RxJava 【发布时间】:2015-03-18 19:04:55 【问题描述】:我在 android 应用程序上使用 Retrofit + RxJava,我问自己如何处理 API 分页以链接调用,直到检索到所有数据。是这样的:
Observable<ApiResponse> getResults(@Query("page") int page);
ApiResponse 对象有一个简单的结构:
class ApiResponse
int current;
Integer next;
List<ResponseObject> results;
API 将返回一个 next 值,直到最后一页。
有什么好方法可以做到这一点?尝试合并一些flatMaps(),但没有成功。
【问题讨论】:
你能澄清你的输入和输出吗?带有描述的方法签名会更好。 【参考方案1】:您可以递归地对其建模:
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
流,它将按顺序到达,并且很可能以页面大小的块的形式到达。
【讨论】:
每天我都会发现一个新的 RxJava 运算符(concatMap 对我来说是新的)。经过测试和批准:) 在这个例子中,有没有办法等待所有结果进来,然后将结果组合成一个可以订阅的响应?toList
可能是最简单的,一旦Observable
完成,它将发出所有元素的单个列表。还有一些其他的运算符用于分组到集合中,例如reduce
。
请注意,我在另一个答案中对此进行了一些改进:***.com/a/29594194/1424355 用于处理递归可能会破坏堆栈的情况。此外,一般来说,它可能只是一个更简单的替代方案。
“递归可能会破坏堆栈”并且它会破坏。 @lopar 我非常感谢您的解决方案,但是您能否添加有关此解决方案导致严重内存泄漏的信息?如果您将链接添加到另一个答案,那就太好了,因为我一开始没有注意到您的最后评论。【参考方案2】:
我已经在类似的帖子中回答了我的解决方案:https://***.com/a/34378263/143733
@Iopar 提供的解决方案的技巧或修改是包含一个可以通过多种方式发出的“触发器”Observable。
在我发布的代码中,它会在处理完一整页元素后发出,但它也可能基于用户单击按钮/滚动而发生。
【讨论】:
【参考方案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]
【讨论】:
以上是关于使用 RxJava 处理分页的主要内容,如果未能解决你的问题,请参考以下文章