RxJava2&改造:如何获取数据页面

时间:2018-05-25 21:45:43

标签: kotlin retrofit rx-java

目标:我想反复调用返回分页数据的Retrofit服务(GET),直到我用尽其页面为止。从第0页到第n页。

首先,我已经查看了Split function documentation these个答案。第一个实际上有效,但我并不过分喜欢递归解决方案,因为它可能导致堆栈溢出。第二次尝试使用调度程序时失败。

这是第二个样本:

Observable.range(0, 5/*Integer.MAX_VALUE*/) // generates page values
    .subscribeOn(Schedulers.io())           // need this to prevent UI hanging
    // gamesService uses Schedulers.io() by default
    .flatMapSingle { page -> gamesService.getGames(page) }
    .takeWhile { games -> games.isNotEmpty() } // games is a List<Game>
    .subscribe(
        { games -> db.insertAll(games) },
        { Logger.e(TAG, it, "Error getting daily games: ${it.message}") }
    )

期待这样做是为了停止gamesService.getGames(page)返回空列表的那一刻。相反,它会继续以不确定的次数命中端点,并增加页面值。我已使用Single.just(intVal)对单元测试进行了一些实验,并确定问题似乎是我的服务在Schedulers.io()上自动订阅。这就是我定义我的Retrofit服务的方式:

private inline fun <reified T> createService(okClient: OkHttpClient): T {
    val rxAdapter = RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io())
    val retrofit = Retrofit.Builder()
        .baseUrl(config.apiEndpoint.endpoint())
        .client(okClient)
        .addCallAdapterFactory(rxAdapter)
        .addConverterFactory(moshiConverterFactory())
        .build()

    return retrofit.create(T::class.java)
}

}

这是我尝试过的另一个想法:

createWithScheduler()

这是另一个案例,它在我引入val atomic = AtomicInteger(0) Observable.generate<Int> { it.onNext(atomic.getAndIncrement()) } .subscribeOn(Schedulers.io()) .flatMapSingle { page -> gamesService.getGames(page) } .takeWhile { games -> games.isNotEmpty() } .subscribe( { games -> dailyGamesDao.insertAll(games) }, { Logger.e(TAG, it, "Error getting daily games: ${it.message}") } ) 之前一直按预期工作。当Scheduler发现空列表时,我希望它停止时,生成器会生成 way 太多的值。

我还尝试了各种takeWhile(concatWith,concatMap等)。

此时,我真的只是在寻找帮助我纠正显而易见(对他们而言)的人,以及我与RxJava运营商明显存在的完全基本的误解。

1 个答案:

答案 0 :(得分:0)

我找到了部分解决方案。 (如果我找到“最终”解决方案,我可以稍后编辑这个答案。)

tl; dr 我应该将Single转换为Observable并使用flatMap重载maxConcurrency参数。例如:

Observable.range(0, SOME_SUFFICIENTLY_LARGE_NUMBER)
    .subscribeOn(Schedulers.io())
    .flatMap({ page -> gamesService.getGames(page).toObservable }, 1 /* maxConcurrency */)
    .takeWhile { games -> games.isNotEmpty() }
    .subscribe(
        { games -> dailyGamesDao.insertAll(games) },
        { Logger.e(TAG, it, "Error getting daily games: ${it.message}") }
    )

基本上就是这样。通过将并发线程数限制为1,我现在正在寻找“一个接一个”的行为。我唯一不喜欢这个,我认为这是一个小小的抱怨,我的基础Observable.range()仍然可以发出很多值 - 比以往任何时候都使用下游Single s / Observable s。

PS:我之前找不到此解决方案的一个原因是我使用的是RxJava 2.1.9。当我把它推到2.1.14时,我可以访问新的重载。哦,好吧。