目标:我想反复调用返回分页数据的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运营商明显存在的完全基本的误解。
答案 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时,我可以访问新的重载。哦,好吧。