Mobile ApplicationSolutions

How to Implement Paging 3 Library in Android Kotlin?

Introduction

Android introduced “Pagination” just because most applications have a large amount of data and display that data in the listing. However, users generally consider only small parts of data listing. Just fetching all data from the network and displaying it in listview or recycler view is not an optimum solution.

The paging library is the easiest way to display data in a listing format. Currently, Paging 3 Library is available with an alpha release, whereas if you want to work with a stable version of Paging Library then Paging 2 is available without Kotlin coroutine flow.

This demographic workflow will be about on Paging 3 Library in Android

Features of Paging 3

Paging 3 library comes with the latest features that might cover all the scenarios of listing the data in any format like (Listview, Recyclerview, GridView etc ..)

  • Support live data
  • Paging 3 library support coroutine flow
  • List separators (Decoration with Item )

Implement Paging 3 Library in Android Kotlin

The below process will guide you that how to implement Paging 3 in your
application.

Implement Paging-3 Library in Android Kotlin

Step 1: Implementation of Library into Project:

You have to implement this library in the Build.gradle folder.

implementation "androidx.paging:paging-runtime-ktx:3.1.0-beta01" 

Step 2: Generating Data Models

The data resource class helps you to get data and retrieve data from the network. This means the network will provide some data and we have to store it in some class which is called data class.

See also  AI-Based Chatbot Applications Uses in 5 Different Industries

PassengerListResponse

@Parcelize
data class PassengerListResponse(
   @SerializedName("totalPassengers") val totalPassengers: Int,
   @SerializedName("totalPages") val totalPages: Int,
   @SerializedName("data") val passengerList: List<Passenger>
) : Parcelable

@Parcelize
data class Passenger(
   @SerializedName("_id") val id: String,
   @SerializedName("name") val name: String,
   @SerializedName("trips")     val trips: Int,
   @SerializedName("__v") val visits: Int
) : Parcelable

As You see PassengerListResponse class, we have several elements that will be available on the network side with the name of the data.

Step 3: Integrate Source File

We need to create a Datasource class which help you to retrieve data from the services and it looks like as mentioned below :

class PassengerItemDataSource(
   private val dataRepository: DataRepository
) : PagingSource<Int, Passenger>() {


   companion object {
       private const val STARTING_PAGE_INDEX = 1
   }

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

       //Retrofit will automatically make suspend functions main-safe so you can call them directly from Dispatchers.Main
       return when (val result = dataRepository.getPassengerListForPage(position, params.loadSize)) {
           is Resource.Failure -> LoadResult.Error(Exception(result.message))
           is Resource.Loading -> LoadResult.Error(Exception())
           is Resource.Success -> {
               LoadResult.Page(
                   data = result.data.passengerList,
                   prevKey = if (position == STARTING_PAGE_INDEX) null else position - 1,
                   nextKey = if (result.data.passengerList.isEmpty()) null else position + 1
               )
           }
       }
   }

   override fun getRefreshKey(state: PagingState<Int, Passenger>): Int? {
       // We need to get the previous key (or next key if previous is null) of the page
       // that was closest to the most recently accessed index.
       // Anchor position is the most recently accessed index
       return state.anchorPosition?.let { anchorPosition ->
           state.closestPageToPosition(anchorPosition)?.prevKey?.plus(1)
               ?: state.closestPageToPosition(anchorPosition)?.nextKey?.minus(1)
       }
   }
}

Step 4: Develop Data Source Factory

After creating the Datasource class, you need to implement Data Source Factory.

The data source Factory class is used to create data sources from the network.

class PassengerDataSourceFactory(private val dataRepository: DataRepository)
{
   fun getPassengers()=Pager(
       config = PagingConfig(
           pageSize = NETWORK_PAGE_SIZE,
           enablePlaceholders = false
       ),
       pagingSourceFactory = { PassengerItemDataSource(dataRepository) }
   ).liveData
}

After creating the Data sources factory, we need to create one adapter class where we can display the list of data.

See also  How to Handle Runtime Permissions in Android Application?

Step 5: Create List Adapter Class

The list adapter class provides the default implementation of listener interfaces. If you inherit the adapter class, you will not be provided with the implementation of all the methods of listener interfaces so it saves codes.

PasangerListAdapter:

class PassengerListAdapter :
   PagingDataAdapter<Passenger, PassengerListAdapter.PassengerViewHolder>(PassengerListDiffCallback()) {

   override fun onCreateViewHolder(
       parent: ViewGroup,
       viewType: Int
   ): PassengerViewHolder {
       val inflater = LayoutInflater.from(parent.context)
       val binding = RawPassengerItemBinding.inflate(inflater)
       return PassengerViewHolder(binding)
   }

   override fun onBindViewHolder(
       holder: PassengerViewHolder,
       position: Int
   ) {
       val item: Passenger? = getItem(position)
       item?.let {
           holder.bind(item)
       }
   }

   override fun onBindViewHolder(
       holder: PassengerViewHolder,
       position: Int,
       payloads: MutableList<Any>
   ) {
       if (payloads.isNullOrEmpty()) {
           super.onBindViewHolder(holder, position, payloads)
       } else {
           val newItem = payloads[0] as Passenger
           holder.bind(newItem)
       }
   }

   inner class PassengerViewHolder(private val rawPassengerItemBinding: RawPassengerItemBinding) :
       RecyclerView.ViewHolder(rawPassengerItemBinding.root) {

       fun bind(passenger: Passenger) {
           rawPassengerItemBinding.passenger = passenger
       }
   }

   class PassengerListDiffCallback : DiffUtil.ItemCallback<Passenger>() {
       override fun areItemsTheSame(oldItem: Passenger, newItem: Passenger) =
           oldItem.id == newItem.id

       override fun areContentsTheSame(
           oldItem: Passenger,
           newItem: Passenger
       ) = oldItem == newItem

       override fun getChangePayload(oldItem: Passenger, newItem: Passenger): Any? {
           if (oldItem != newItem) {
               return newItem
           }

           return super.getChangePayload(oldItem, newItem)
       }
   }
}

In this adapter class, we have some override method which is used to set our raw items.

Override Method Of Adapter:

1. OnCreateViewHolder()
2. onBindViewHolder()
3. And ViewHolder Class ()

The below code describes how to create an adapter class.

class PassengerListAdapter :
   PagingDataAdapter<Passenger, PassengerListAdapter.PassengerViewHolder>(PassengerListDiffCallback()) {

   override fun onCreateViewHolder(
       parent: ViewGroup,
       viewType: Int
   ): PassengerViewHolder {
       val inflater = LayoutInflater.from(parent.context)
       val binding = RawPassengerItemBinding.inflate(inflater)
       return PassengerViewHolder(binding)
   }

   override fun onBindViewHolder(
       holder: PassengerViewHolder,
       position: Int
   ) {
       val item: Passenger? = getItem(position)
       item?.let {
           holder.bind(item)
       }
   }

   override fun onBindViewHolder(
       holder: PassengerViewHolder,
       position: Int,
       payloads: MutableList<Any>
   ) {
       if (payloads.isNullOrEmpty()) {
           super.onBindViewHolder(holder, position, payloads)
       } else {
           val newItem = payloads[0] as Passenger
           holder.bind(newItem)
       }
   }

   inner class PassengerViewHolder(private val rawPassengerItemBinding: RawPassengerItemBinding) :
       RecyclerView.ViewHolder(rawPassengerItemBinding.root) {

       fun bind(passenger: Passenger) {
           rawPassengerItemBinding.passenger = passenger
       }
   }

   class PassengerListDiffCallback : DiffUtil.ItemCallback<Passenger>() {
       override fun areItemsTheSame(oldItem: Passenger, newItem: Passenger) =
           oldItem.id == newItem.id

       override fun areContentsTheSame(
           oldItem: Passenger,
           newItem: Passenger
       ) = oldItem == newItem

       override fun getChangePayload(oldItem: Passenger, newItem: Passenger): Any? {
           if (oldItem != newItem) {
               return newItem
           }

           return super.getChangePayload(oldItem, newItem)
       }
   }
}

Step 6: Loading Adapter in fragment or Activity

This code is Used how to access pagination in our activity or fragment

passengerListAdapter.addLoadStateListener { loadState ->
   when (val state = loadState.source.refresh) {
       is LoadState.NotLoading -> {
           /**
            * Setting up the views as per your requirement
            */
         }
       is LoadState.Loading -> {
           /**
            * Setting up the views as per your requirement
            */
         
       }
       is LoadState.Error -> {
           /**
            * Setting up the views as per your requirement
            */
         
         Youractivity?.showMessage(state.error.message.orEmpty())
       }
   }
}
Example of Pagination
Example of Pagination

Conclusion

To conclude, Pagination 3 is widely used in most applications where there is a list of data available in the android application. Implementation of pagination provides an efficient user experience. Paging 3 also enables developers to implement pagination with ease and better accuracy.

See also  Fundamentals of Using Kotlin Coroutines in Android

We hope you have enjoyed reading this article and found it helpful. Good Luck with your implementation of Pagination using the Paging 3 library in Android.

Android Custom Library CTA1

FAQ

1. Why do we use the paging 3 library for pagination?

We can use the paging 3 library for pagination. Because it provides first-class Kotlin support to handle easy or complex data operations like data loading from network, database or combination of different data sources. And the paging 3 library can also support Kotlin coroutine flow.

2. Can we use the Paging 3 Library in Java?

Yes, We can use the paging 3 Library in java as well.

    Need an IT Experts? Get a Free Consultation!

    lets start your project

    Related Articles