So it turned out that the only meaningful approach is to add the data from the second API call within the DataSource
. The reason for that is that the PagedList is considered immutable by the paging library. So before we either call LoadInitialCallback.onResult()
or LoadCallback.onResult()
all data should be prepared and available.
My DataSource looks like this now:
override fun loadInitial(params: LoadInitialParams<Int>, callback: LoadInitialCallback<Int, Car>) {
val request = dataService.getCars(1) // load page 1 of all cars
val response = request.execute()
val items = response.body()?.values ?: emptyList()
// we got the initial batch of cars -> now check them for prices
fetchPrices(items, callback, nextPageKey = 2)
}
override fun loadAfter(params: LoadParams<Int>, callback: LoadCallback<Int, Repository>) {
val request = dataService.getCars(params.key)
request.enqueue(object : Callback<Cars> {
override fun onResponse(call: Call<Cars>, response: Response<Cars>) {
if (response.isSuccessful) {
val items = response.body()?.values ?: emptyList()
retry = null
// we got a batch of cars -> now check them for prices
fetchPrices(items, afterCallback = callback, nextPageKey = params.key + 1)
}
}
override fun onFailure(call: Call<Repositories>, t: Throwable) {
...
}
})
}
/**
* This method is checking all of the given [cars] for having a price.
* If a car has a price, this is added to the car.
* If all cars were checked, the onResult-callback of this DataSource is called
* to signal the completion of getting the paged data.
*/
private fun fetchPrices(
repositories: List<Car>,
initialCallback: LoadInitialCallback<Int, Car>? = null,
afterCallback: LoadCallback<Int, Car>? = null,
nextPageKey: Int
) {
// used to count the server responses
var checkedPrices = 0
cars.forEach { car ->
// enqueue the price request for this car
val priceRequest = dataService.getPrice(car.id, 1)
priceRequest.enqueue(object : Callback<Prices> {
override fun onFailure(call: Call<Prices>, t: Throwable) {
// ignore failed requests, but still check for completion
// to increase the checkedPrices counter.
checkForCompletion()
}
override fun onResponse(call: Call<Cars>, response: Response<Cars>) {
if (!response.isSuccessful || response.body() == null) return
val prices = (response.body() as Prices).values
if (!prices.isNullOrEmpty()) {
car.price = prices.first()
}
checkForCompletion()
}
// check if we got server responses for all cars.
// If yes, call either the initialCallback or the afterCallback
private fun checkForCompletion() {
checkedPrices++
if (checkedPrices >= cars.size) {
initialCallback?.onResult(repositories, 0, nextPageKey)
afterCallback?.onResult(repositories, nextPageKey)
}
}
})
}
}