我们如何使用 RxJava 进行分页 Web 服务调用,其中每个页面都依赖于上一页的响应,而无需递归? [英] How Can We Use RxJava for Paginated Web Service Calls, Where Each Page Depends on Previous Page Responses, Without Recursion?
问题描述
Web 服务 API 有时使用分页,其中 Web 服务调用的参数指示要检索的页面.大致可以分为两种:
Web service APIs sometimes use pagination, where parameters to the Web service call indicate what page to retrieve. These can be roughly divided into two types:
请求页面的参数与任何给定的页面响应无关(例如,给我第 3 页,页面大小为 10")
Ones where the parameters to request a page are independent of any given page response (e.g., "give me page #3, with a page size of 10")
请求页面的参数依赖于某些先前页面响应的那些(例如,在标识符为 foo
的项目之后给我接下来的 10 个项目)
Ones where the parameters to request a page are dependent on some previous page response (e.g., "give me the next 10 items after the item with an identifier of foo
)
这个 SO 答案 很好地涵盖了第一个场景,其中 Web 服务只需要一个页码以及我们需要的所有内容从任何给定页面的响应中确定我们是否已完成.
This SO answer covers the first scenario nicely, where the Web service just needs a page number and all we need to determine from any given page's response is whether or not we are done.
这个 SO 答案 涵盖了第二种情况,但它依赖于递归,因此对于大型数据集,我们会死带有 StackOverflowError
.
This SO answer covers the second scenario, but it relies upon recursion, and so for large data sets we will die with a StackOverflowError
.
与 Relay 兼容的基于 GraphQL 的 Web 服务(例如,GitHub 的 API)将大量使用第二种情况,如 Relay 的分页规范 要求您提供来自先前响应的光标",以获取该光标位置之后的下一个项目.因此,我正在尝试为此找出一种非递归方法,它仍然将所有内容打包到一个主 Observable
中,就像这两个答案一样.
A Relay-compatible GraphQL-powered Web service (e.g., GitHub's API) will make heavy use of the second scenario, as Relay's specification for pagination requires you to provide a "cursor" from a previous response to get the next items after that cursor position. So, I am trying to figure out a non-recursive approach for this, that still wraps everything up into a single master Observable
, the way those two answers do.
推荐答案
如果 Web Service API 阻塞或者您愿意阻塞,那么解决方案很简单
If Web Service API is blocking or you are willing to block then the solution is easy
Observable.generate(() -> new ApiResponse(page), (s, emitter) -> {
ApiResponse r = getResults(s.next);
emitter.onNext(r);
if (r.next == null) emitter.onComplete();
return r;
});
使用递归答案中的符号.
using notation from recursive answer.
如果不需要阻塞,您可以使用 RxJava2ExtensionsFlowableTransformers.expand> 像这样
If blocking is not desirable you can use FlowableTransformers.expand
from RxJava2Extensions like so
Flowable
.just(new ApiResponse(page))
.compose(FlowableTransformers.expand(r -> r.next == null ? Flowable.empty() : getResults(r.next)));
这篇关于我们如何使用 RxJava 进行分页 Web 服务调用,其中每个页面都依赖于上一页的响应,而无需递归?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!