如何向 PagedList 中的每个项目添加数据
How to add data to each item in a PagedList
假设我正在使用 API 来获取汽车列表。此列表已实现,并且使用 PagedList with a PageKeyedDataSource 可以正常工作。汽车正在显示,当我向下滚动时,新汽车被加载并附加到 UI。不错!
现在我想显示每辆车的附加数据。说说汽车的价格吧。此附加数据来自另一个 API 端点。据我所知,我必须找到一种方法来使用 DataSource.map()
或 DataSource.mapByPage()
为每辆车调用 API 以接收其价格。然后必须以某种方式将该价格添加到列表项中。
我正在使用架构组件(LiveData、数据绑定、MVVM 等)中的所有好东西。现在我没有数据库,我想保持这样。 Retrofit 正在为我做所有的缓存。
我该如何处理?
所以事实证明,唯一有意义的方法是在 DataSource
中添加来自第二个 API 调用的数据。原因是分页库认为 PagedList 是不可变的。因此,在我们调用 LoadInitialCallback.onResult()
或 LoadCallback.onResult()
之前,所有数据都应该准备好并可用。
我的数据源现在看起来像这样:
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)
}
}
})
}
}
假设我正在使用 API 来获取汽车列表。此列表已实现,并且使用 PagedList with a PageKeyedDataSource 可以正常工作。汽车正在显示,当我向下滚动时,新汽车被加载并附加到 UI。不错!
现在我想显示每辆车的附加数据。说说汽车的价格吧。此附加数据来自另一个 API 端点。据我所知,我必须找到一种方法来使用 DataSource.map()
或 DataSource.mapByPage()
为每辆车调用 API 以接收其价格。然后必须以某种方式将该价格添加到列表项中。
我正在使用架构组件(LiveData、数据绑定、MVVM 等)中的所有好东西。现在我没有数据库,我想保持这样。 Retrofit 正在为我做所有的缓存。
我该如何处理?
所以事实证明,唯一有意义的方法是在 DataSource
中添加来自第二个 API 调用的数据。原因是分页库认为 PagedList 是不可变的。因此,在我们调用 LoadInitialCallback.onResult()
或 LoadCallback.onResult()
之前,所有数据都应该准备好并可用。
我的数据源现在看起来像这样:
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)
}
}
})
}
}