Pagination in RecyclerView kotlin

07-Jan-2025

Pagination in RecyclerView kotlin

Output:





1/ Add the below dependencies in your build.gradle file dependencies block and sync 



// retrofit2
implementation("com.squareup.retrofit2:retrofit:2.11.0")
implementation("com.squareup.retrofit2:converter-gson:2.11.0")
//glide
implementation("com.github.bumptech.glide:glide:4.16.0")
annotationProcessor("com.github.bumptech.glide:compiler:4.16.0")

// paging3
implementation( "androidx.paging:paging-runtime:3.3.5")



2/  Create and modify item_product.xml file



<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="8dp">

<ImageView
android:id="@+id/product_thumbnail"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerCrop" />

<TextView
android:id="@+id/product_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:textSize="18sp"
android:paddingTop="8dp" />

<TextView
android:id="@+id/product_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="4dp" />
<TextView
android:id="@+id/product_price"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"
android:paddingTop="8dp" />
</LinearLayout>
</androidx.cardview.widget.CardView>




3/  Modify the activity_main.xml file



<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">

<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

<ProgressBar
android:id="@+id/progressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"


/>

</LinearLayout>

<ProgressBar
android:id="@+id/progressBar2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"

/>

</RelativeLayout>



4/ Add Product class



package com.microappvalley.paginationinrecyclerviewkotlin

data class Product(
val id: Int,
val title: String,
val description: String,
val price: Double,
val thumbnail: String
)


5/ Add ProductResponse class



package com.microappvalley.paginationinrecyclerviewkotlin

data class ProductResponse(
val products: List<Product>,
val total: Int,
val skip: Int,
val limit: Int
)



6/ Add RetrofitClient object



package com.microappvalley.paginationinrecyclerviewkotlin

import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory

object RetrofitInstance {
private val retrofit by lazy {
Retrofit.Builder()
.baseUrl("https://dummyjson.com/")
.addConverterFactory(GsonConverterFactory.create())
.build()
}

val api: ApiService by lazy {
retrofit.create(ApiService::class.java)
}
}




7/ Add ApiService interface




package com.microappvalley.paginationinrecyclerviewkotlin

import retrofit2.http.GET
import retrofit2.http.Query

interface ApiService {
@GET("products")
suspend fun getProducts(
@Query("limit") limit: Int,
@Query("skip") skip: Int
): ProductResponse
}



8/ Add ProductAdapter



package com.microappvalley.paginationinrecyclerviewkotlin

import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide

class ProductAdapter : PagingDataAdapter<Product, ProductAdapter.ProductViewHolder>(PRODUCT_COMPARATOR) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_product, parent, false)
return ProductViewHolder(view)
}

override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
val product = getItem(position)
if (product != null) {
holder.bind(product)
}
}

inner class ProductViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val title = itemView.findViewById<TextView>(R.id.product_title)
private val description = itemView.findViewById<TextView>(R.id.product_description)
private val price = itemView.findViewById<TextView>(R.id.product_price)
private val thumbnail = itemView.findViewById<ImageView>(R.id.product_thumbnail)

fun bind(product: Product) {
title.text = product.title
description.text = product.description
price.text = "$${product.price}"
Glide.with(itemView.context).load(product.thumbnail).into(thumbnail)
}
}

companion object {
private val PRODUCT_COMPARATOR = object : DiffUtil.ItemCallback<Product>() {
override fun areItemsTheSame(oldItem: Product, newItem: Product): Boolean {
return oldItem.id == newItem.id
}

override fun areContentsTheSame(oldItem: Product, newItem: Product): Boolean {
return oldItem == newItem
}
}
}
}



9/ Add ProductPagingSource


package com.microappvalley.paginationinrecyclerviewkotlin

import androidx.paging.PagingSource
import androidx.paging.PagingState

class ProductPagingSource(private val apiService: ApiService) : PagingSource<Int, Product>() {

override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Product> {
val page = params.key ?: 0
return try {
val response = apiService.getProducts(limit = 10, skip = page)
LoadResult.Page(
data = response.products,
prevKey = if (page == 0) null else page - 10,
nextKey = if (response.products.isEmpty()) null else page + 10
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}

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



10/ Modify MainActivity.kt




package com.microappvalley.paginationinrecyclerviewkotlin

import android.os.Bundle
import android.widget.ProgressBar
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.flow.collectLatest

class MainActivity : AppCompatActivity() {
private lateinit var recyclerView: RecyclerView
private lateinit var progressBar: ProgressBar
private lateinit var productAdapter: ProductAdapter

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

recyclerView = findViewById(R.id.recyclerView)
progressBar = findViewById(R.id.progressBar)

productAdapter = ProductAdapter()
recyclerView.layoutManager = LinearLayoutManager(this@MainActivity)
recyclerView.adapter = productAdapter

val pager = Pager(
config = PagingConfig(pageSize = 10, enablePlaceholders = false),
pagingSourceFactory = { ProductPagingSource(RetrofitInstance.api) }
)

lifecycleScope.launchWhenStarted {
pager.flow.collectLatest { pagingData ->
productAdapter.submitData(pagingData)
}
}
}

}




Comments