Search code examples
androidkotlinandroid-recyclerviewandroid-paging-3

How to stop looping same recycler view data in Android?


In my API, there is no pageSize or unique id for each products is there, but I still implemented Paging 3 library and comparator inside adapter as well with live data for latest changes.

Now the problem is: Suppose total only 10 items are there in my API, and I fetchd it and showing in list. But once I scroll 10 items, again that 10 items are showing, and again...and infinite!!

I suspect 3 mistakes of mine, one because of wrong implementation with paging (next prev key), or 2nd problem is because of comparator and 3rd, I overriden getRefreshKey and passed state.anchorPosition.

Code:

ProductPagingSource

class ProductPagingSource(
    private val productApi: ProductApi,
) : PagingSource<Int, Products>() {

    override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Products> {
        val position = params.key ?: PRODUCT_STARTING_PAGE_INDEX

        return try {
            val response =
                productApi.getProducts() //Not added load size, position and other params, because in API, there is no data related to that.
            val products = response.products

            LoadResult.Page(
                data = products,
                prevKey = if (position == PRODUCT_STARTING_PAGE_INDEX) null else position - 1,
                nextKey = if (products.isEmpty()) null else position + 1
            )
        } catch (exception: IOException) {
            LoadResult.Error(exception)
        } catch (exception: HttpException) {
            LoadResult.Error(exception)
        }
    }

    override fun getRefreshKey(state: PagingState<Int, Products>): Int? {
        return state.anchorPosition
    }
}

ProductAdapter

class ProductAdapter(context: Context?) :
    PagingDataAdapter<Products, ProductAdapter.ProductViewHolder>(PRODUCT_COMPARATOR) {
    private lateinit var mContext: Context

    init {
        if (context != null) {
            mContext = context
        }
    }

.
.
.

 private val PRODUCT_COMPARATOR = object : DiffUtil.ItemCallback<Products>() {
            override fun areItemsTheSame(oldItem: Products, newItem: Products) =
                oldItem.name == newItem.name

            override fun areContentsTheSame(oldItem: Products, newItem: Products) =
                oldItem == newItem
        }
    }
}

Solution

  • Without the API documentation, I can only answer this in a general manner:

    When you tell it to always fetch the same data, it will probably always fetch the same data - this means that our business logic is flawed, because productApi.getProducts() needs to fetch per key (which is often called the "next page token"). In case the API should not to support pagination, you'd have to use a repository and then query the local SQLite with paging support.