I'm attempting to get pagination up and workning with Google's new library, but seeing some odd behavior. I'm not sure where I am going wrong.
I'm followig MVP and also using some dagger injection for testability.
In the view:
val adapter = ItemsAdapter()
viewModel.getItems(itemCategoryId, keywords).observe(this, Observer {
Log.d(TAG, "Items updated $it")
adapter.setList(it)
})
The data source factory:
class ItemDataSourceFactory(
private val api: Api,
private val retryExecutor: Executor
) : DataSource.Factory<Long, Item> {
private val mutableLiveData = MutableLiveData<ItemDataSource>()
override fun create(): DataSource<Long, Item> {
val source = ItemDataSource(api, retryExecutor)
mutableLiveData.postValue(source)
return source
}
}
The data source:
class ItemDataSource(
private val api: Api,
private val retryExecutor: Executor
): ItemKeyedDataSource<Long, Item>() {
companion object {
private val TAG = ItemKeyDataSource::class.java
}
override fun getKey(item: Item): Long = item.id
override fun loadBefore(params: LoadParams<Long>, callback: LoadCallback<Item>) {
// ignored, since we only ever append to our initial load
}
override fun loadInitial(params: LoadInitialParams<Long>, callback: LoadInitialCallback<Item>) {
api.loadItems(1, params.requestedLoadSize)
.subscribe({
Logger.d(TAG, "Page 1 loaded. Count ${params.requestedLoadSize}.\nItems: ${it.items}")
callback.onResult(it.items as MutableList<Item>, 0, it.item.size)
}, {})
}
override fun loadAfter(params: LoadParams<Long>, callback: LoadCallback<Item>) {
api.loadItems(params.key, params.requestedLoadSize)
.subscribe({
Logger.d(TAG, "Page ${params.key} loaded. Count ${params.requestedLoadSize}.\nItems: ${it.items}")
callback.onResult(it.itemsas MutableList<Item>)
}, {})
}
}
And the view model:
class ItemsViewModel @Inject internal constructor(
private val repository: ItemsMvp.Repository
): ViewModel(), ItemsMvp.Model {
override fun items(categoryId: Long, keywords: String?): LiveData<PagedList<Item>> {
return repository.items(categoryId, keywords)
}
}
And the repository layer:
class ItemsRepository @Inject internal constructor(
private val api: Api,
) : ItemsMvp.Repository {
companion object {
const val DEFAULT_THREAD_POOL_SIZE = 5
const val DEFAULT_PAGE_SIZE = 20
}
private val networkExecutor = Executors.newFixedThreadPool(DEFAULT_THREAD_POOL_SIZE)
private val pagedListConfig = PagedList.Config.Builder()
.setEnablePlaceholders(false)
.setInitialLoadSizeHint(DEFAULT_PAGE_SIZE)
.setPageSize(DEFAULT_PAGE_SIZE)
.build()
override fun items(categoryId: Long, keywords: String?): LiveData<PagedList<Item>> {
val sourceFactory = ItemDataSourceFactory(api, networkExecutor)
// provide custom executor for network requests, otherwise it will default to
// Arch Components' IO pool which is also used for disk access
return LivePagedListBuilder(sourceFactory, pagedListConfig)
.setBackgroundThreadExecutor(networkExecutor)
.build()
}
}
The issue is I'm not getting an update to the view after the first page is loaded.
I see this log from the onCreate():
Items updated []
but then after when the data source returns the items, I see these logs:
Page 1 loaded. Count 20.
Items: [Item(....)]
BUT I never see the view that's subscribing to the view model get an update to set the list on the adapter. If you are curiousI'm using a PagedListAdapter.
I had two mistakes...
I made those two adjustments and now everything is behaving as expected.