Rx java 在没有递归的情况下,我们如何使用RxJava进行分页Web服务调用,其中每个页面都依赖于以前的页面响应?
Web服务API有时使用分页,其中Web服务调用的参数指示要检索的页面。这些可大致分为两类:Rx java 在没有递归的情况下,我们如何使用RxJava进行分页Web服务调用,其中每个页面都依赖于以前的页面响应?,rx-java,rx-java2,Rx Java,Rx Java2,Web服务API有时使用分页,其中Web服务调用的参数指示要检索的页面。这些可大致分为两类: 请求页面的参数独立于任何给定的页面响应(例如,“给我页面3,页面大小为10”) 请求页面的参数取决于前一页的响应(例如,“在标识符为foo的项目后,给我接下来的10个项目) 很好地介绍了第一个场景,其中Web服务只需要一个页码,我们需要从任何给定页面的响应中确定我们是否完成了 介绍了第二种情况,但它依赖于递归,因此对于大型数据集,我们将使用stackoverflowerrror 中继兼容的Graph
- 请求页面的参数独立于任何给定的页面响应(例如,“给我页面3,页面大小为10”)
- 请求页面的参数取决于前一页的响应(例如,“在标识符为
的项目后,给我接下来的10个项目)foo
stackoverflowerrror
中继兼容的GraphQL支持的Web服务(例如GitHub的API)将大量使用第二种场景,因为需要提供“游标”“从上一个响应获取光标位置后的下一个项目。因此,我试图找出一种非递归的方法来解决这个问题,它仍然将所有内容都封装到一个主
可观察的,就像这两个答案所做的那样。如果Web服务API被阻塞,或者您愿意阻塞,那么解决方案很简单
Observable.generate(() -> new ApiResponse(page), (s, emitter) -> {
ApiResponse r = getResults(s.next);
emitter.onNext(r);
if (r.next == null) emitter.onComplete();
return r;
});
使用递归答案的符号
如果不需要阻塞,您可以使用FlowableTransformers。从类似的方式展开
我不知道是否正确,但我相信您可以在RxJava上使用SyncOnSubscribe.createStateful
来解决这个问题
查看我的样本:
class SimpleTest {
@Test
fun testRequestTenPages() {
getPaginatedDataFromApi()
.take(10)
.subscribe { println(it) }
}
fun apiCall(previous: Response? = null) : Response {
return previous?.let {
val newPage = it.page + 1
previous.copy(id = "${it.id}_$newPage", page = newPage)
} ?: Response("1", 1)
}
fun getPaginatedDataFromApi(): Observable<Response> {
val syncOnSubscribe = SyncOnSubscribe.createStateful<Response?, Response>(
{ null },
{ previous, observer ->
val response = apiCall(previous)
observer.onNext(response)
return@createStateful response
}
)
return Observable.create(syncOnSubscribe)
}
data class Response(val id: String, val page: Int)
}
您仍然可以使用“递归”解决方案,并添加一些异步边界运算符-例如Flowable.observeOn(Schedulers.io())
-在内部Flowable
调用web服务API阻塞,还是返回observeable?问题是为了使用API,需要等待上一个结果完成,才能请求下一个结果。若你们愿意阻止,那个么解决方案很容易。这是一个有趣的观点。我一直坚持使用现有的基于的可观察的API,但我可以切换到使用阻塞调用,并如您所示进行包装。我要试一试——非常感谢!请参阅更新答案中的第二部分,该部分不阻塞,但需要额外的库。这相当于另一个答案中的Observable.generate,类似于它也需要API调用阻塞
class SimpleTest {
@Test
fun testRequestTenPages() {
getPaginatedDataFromApi()
.take(10)
.subscribe { println(it) }
}
fun apiCall(previous: Response? = null) : Response {
return previous?.let {
val newPage = it.page + 1
previous.copy(id = "${it.id}_$newPage", page = newPage)
} ?: Response("1", 1)
}
fun getPaginatedDataFromApi(): Observable<Response> {
val syncOnSubscribe = SyncOnSubscribe.createStateful<Response?, Response>(
{ null },
{ previous, observer ->
val response = apiCall(previous)
observer.onNext(response)
return@createStateful response
}
)
return Observable.create(syncOnSubscribe)
}
data class Response(val id: String, val page: Int)
}
Response(id=1, page=1)
Response(id=1_2, page=2)
Response(id=1_2_3, page=3)
Response(id=1_2_3_4, page=4)
Response(id=1_2_3_4_5, page=5)
Response(id=1_2_3_4_5_6, page=6)
Response(id=1_2_3_4_5_6_7, page=7)
Response(id=1_2_3_4_5_6_7_8, page=8)
Response(id=1_2_3_4_5_6_7_8_9, page=9)
Response(id=1_2_3_4_5_6_7_8_9_10, page=10)