Rx java 在没有递归的情况下,我们如何使用RxJava进行分页Web服务调用,其中每个页面都依赖于以前的页面响应?

Rx java 在没有递归的情况下,我们如何使用RxJava进行分页Web服务调用,其中每个页面都依赖于以前的页面响应?,rx-java,rx-java2,Rx Java,Rx Java2,Web服务API有时使用分页,其中Web服务调用的参数指示要检索的页面。这些可大致分为两类: 请求页面的参数独立于任何给定的页面响应(例如,“给我页面3,页面大小为10”) 请求页面的参数取决于前一页的响应(例如,“在标识符为foo的项目后,给我接下来的10个项目) 很好地介绍了第一个场景,其中Web服务只需要一个页码,我们需要从任何给定页面的响应中确定我们是否完成了 介绍了第二种情况,但它依赖于递归,因此对于大型数据集,我们将使用stackoverflowerrror 中继兼容的Graph

Web服务API有时使用分页,其中Web服务调用的参数指示要检索的页面。这些可大致分为两类:

  • 请求页面的参数独立于任何给定的页面响应(例如,“给我页面3,页面大小为10”)

  • 请求页面的参数取决于前一页的响应(例如,“在标识符为
    foo
    的项目后,给我接下来的10个项目)

很好地介绍了第一个场景,其中Web服务只需要一个页码,我们需要从任何给定页面的响应中确定我们是否完成了

介绍了第二种情况,但它依赖于递归,因此对于大型数据集,我们将使用
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)