Goal: I want to repeatedly call a Retrofit service (GET) that returns paged data, until I've exhausted its pages. Going from page 0 to page n.
First, I've looked at these two answers already. The first actually works, but I'm not overly fond of the recursive solution as it could lead to stack overflow. The second fails the moment you try to use a scheduler.
Here's a sample of the second:
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}") }
)
What I expect this to do is stop the moment that gamesService.getGames(page)
returns an empty list. Instead, it continues hitting the endpoint for an indeterminate number of times, with incrementing page values. I have experimented a bit in unit tests with Single.just(intVal)
and determined that the problem appears to be the fact that my service is automatically subscribed on Schedulers.io()
. This is how I define my Retrofit services:
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)
}
It's really not an option to not use createWithScheduler()
here.
Here's another idea I tried:
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}") }
)
This is another case where it worked as expected right up until I introduced a Scheduler
. The generator generates way too many values, when I'm expecting it to stop when the takeWhile
discovers an empty list.
I've also tried various kinds of concat
(concatWith, concatMap, etc).
At this point, I'm really just looking for someone to help me correct the obvious (to them) and completely basic misunderstanding I clearly have with RxJava operators.