2

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!

Sergei Mikhailovskii
  • 2,100
  • 2
  • 21
  • 43

0 Answers0