Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to implement a cursor based pagination with Paging Library 3.0 in Android?

I am consuming a rest API that uses cursor based pagination to show some results. I am wondering if I can use Paging Library 3.0 to paginate it. I have been looking through some mediums and docs and can't seem to find a way to implement it. If any of you has come around any solution, I would be so happy to hear from it!

The api response pagination looks like this:

"paging": {
    "previous": false,
    "next": "https://api.acelerala.com/v1/orders/?store_id=4&after=xyz",
    "cursors": {
        "before": false,
        "after": "xyz"
    }
}
like image 621
Mateo Hervas Avatar asked Nov 15 '25 18:11

Mateo Hervas


1 Answers

Thanks to @Đặng Anh Hào I was able to get on track. As my cursor is a String and not at Int, the Paging Source load function looks like this:

override suspend fun load(params: LoadParams<String>): LoadResult<String, Order> {
    return try{
        val response = service.getOrders(query,params.key?:"",10)
        val nextKey = if(response.paging?.cursors?.after=="false") null else response.paging?.cursors?.after
        val prevKey = if(response.paging?.cursors?.before=="false") null else response.paging?.cursors?.before
        LoadResult.Page(response.data?.toOrderList()?:emptyList(),prevKey,nextKey)
    }catch (exception: IOException) {
        LoadResult.Error(exception)
    } catch (exception: retrofit2.HttpException) {
        LoadResult.Error(exception)
    }
}

and the onrefreshkey looks like this:

override fun getRefreshKey(state: PagingState<String, Order>): String? {
    return state.anchorPosition?.let {
        state.closestItemToPosition(it)?.orderId
    }
}

The repository method looks like this:

fun getOrdersPaginated(storeId: String): Flow<PagingData<Order>> {
    return Pager(
        config = PagingConfig(enablePlaceholders = false,pageSize = 10),
        pagingSourceFactory = {PagingSource(apiService,storeId)}
    ).flow

}

And the View Model method is like this:

private val _pagedOrders = MutableLiveData<PagingData<Order>>()
val orders get() = _pagedOrders

private var currentQueryValue: String? = null
private var currentSearchResult: Flow<PagingData<Order>>? = null

fun getOrdersPaginated(storeId: String) {
    viewModelScope.launch {
        currentQueryValue = storeId
        val newResult: Flow<PagingData<Order>> = repository.getOrdersPaginated(storeId)
            .cachedIn(viewModelScope)
        currentSearchResult = newResult
        currentSearchResult!!.collect {
            _pagedOrders.value = it
        }
    }
}

The activity calls the paging like this:

private var searchJob: Job? = null

private fun getOrders() {
    viewModel.getOrdersPaginated(storeId)
}

private fun listenForChanges() {
    viewModel.orders.observe(this, {
        searchJob?.cancel()
        searchJob = lifecycleScope.launch {
            ordersAdapter.submitData(it)
        }
    })
}

And finally the adapter is the same as a ListAdapter, the only thing that changes is that it now extends PagingDataAdapter<Order, OrderAdapter.ViewHolder>(OrdersDiffer)

For a more detailed tutorial on how to do it, I read this codelab

like image 106
Mateo Hervas Avatar answered Nov 18 '25 09:11

Mateo Hervas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!