I tried to implement the pagination with Paging 3 library. For this purpose I created fake request in Requests
class:
fun getBerubyMerchantsByFilter(body: BerubyMerchantsByFilterRequest) = Single.just(
BerubyMerchantsByFilterResponse(
merchants = mutableListOf(
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 1,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 2,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 3,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 5 + 4,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 5,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 6,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 7,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 8,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 9,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
),
BerubiExclusiveOfferResponse(
(body.page ?: 0) * 11 + 10,
"name",
"category",
1,
"cashback",
"https://www.lomsnesvet.ca/wp-content/uploads/sites/21/2019/08/Kitten-Blog-683x1024.jpg"
)
)
)
)
First param which is passed to constructor is id. So, in this case I expect to receive the infinite list as each request will return the page filled with new elements. Then I created the DataSource
:
class BerubyMerchantsDataSource constructor(
private val requests: Requests,
private val requestBody: BerubyMerchantsByFilterRequest
) : RxPagingSource<Int, BerubiExclusiveOfferResponse>() {
override fun getRefreshKey(state: PagingState<Int, BerubiExclusiveOfferResponse>) =
state.anchorPosition?.let { anchorPosition ->
val anchorPage = state.closestPageToPosition(anchorPosition)
anchorPage?.prevKey?.plus(1) ?: anchorPage?.nextKey?.minus(1)
}
override fun loadSingle(params: LoadParams<Int>): Single<LoadResult<Int, BerubiExclusiveOfferResponse>> {
val page = params.key ?: 1
requestBody.page = page
return requests.getBerubyMerchantsByFilter(requestBody)
.subscribeOn(Schedulers.io())
.map {
toLoadResult(it, page, 10)
}.onErrorReturn {
LoadResult.Error(it)
}
}
private fun toLoadResult(
response: BerubyMerchantsByFilterResponse,
currentPage: Int,
pageSize: Int
): LoadResult<Int, BerubiExclusiveOfferResponse> {
Timber.d("Loading page $currentPage")
val nextKey = if ((response.merchants?.size ?: 0) < pageSize) null else currentPage + 1
val prevKey = if (currentPage == 1) null else currentPage - 1
return LoadResult.Page(
response.merchants ?: listOf(),
prevKey,
nextKey
)
}
}
For this case I decided to set page size to 10. In the fragment's onResume
I added observer:
CompositeDisposable().add(
controller.getMerchants().subscribe {
CoroutineScope(Dispatchers.Main).launch {
berubyMerchantsAdapter?.submitData(it)
}
}
)
to Observable which is located in Presenter:
@ExperimentalCoroutinesApi
override fun getMerchants() = Pager(PagingConfig(10)) {
BerubyMerchantsDataSource(requests, requestModel)
}.observable
Also I created the adapter:
class BerubyMerchantsAdapter(diffCallback: DiffUtil.ItemCallback<BerubiExclusiveOfferResponse>) :
PagingDataAdapter<BerubiExclusiveOfferResponse, BerubyMerchantsAdapter.ViewHolder>(diffCallback) {
@SuppressLint("NonConstantResourceId")
inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
@BindView(R.id.iv_merchant_logo)
internal lateinit var ivMerchantLogo: AppCompatImageView
@BindView(R.id.tv_merchant_name)
internal lateinit var tvMerchantName: AppCompatTextView
@BindView(R.id.tv_merchant_category)
internal lateinit var tvMerchantCategory: AppCompatTextView
@BindView(R.id.tv_merchant_cashback)
internal lateinit var tvMerchantCashback: AppCompatTextView
init {
ButterKnife.bind(this, itemView)
}
fun bindData(item: BerubiExclusiveOfferResponse) {
Glide.with(itemView.context).load(item.logoUrl).into(ivMerchantLogo)
tvMerchantName.text = item.name
tvMerchantCategory.text = item.category
tvMerchantCashback.text = item.cashback
}
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
getItem(position)?.let(holder::bindData)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) = ViewHolder(
LayoutInflater.from(parent.context).inflate(
R.layout.beruby_merchant_item, parent, false
)
)
}
And setting data to it by calling submitList()
But when I run the app I see that first two pages are loaded immediately and when I scroll to the bottom new pages are not loaded. So, what's the matter and what I do wrong? Thanks in advance for any help!