How to Use the Paging 3 Library in Android
Paging 3.0 is a major update over the previous versions of Paging Architecture Component of Android.
Most apps displays a large list of data to the users, but at a particular time the user sees only a small chunk of data in your app, so fetching all the data from the network is not an efficient solution. The solution is to fetch small chunks of data at a time, and as soon as the user reach at the end of the list, then the app will load more data. This is called Paging.
With the release of Android 11 beta, Google also updated the Paging architectural components library for android. Paging 3 greatly simplifies implementing paging in your android app.
What’s New in Paging 3.0
Paging 3.0 is significantly different from the earlier versions of Paging Library. Some of the new features of Paging 3.0 includes:
- Support for Kotlin coroutines, Flow, as well as LiveData and RxJava.
- Built in support for error handling, refresh and retry functionality.
- Built in support for loading state headers, footers and list separators.
- In memory caching of data, ensures efficient use of system resources.
- Prevents api request duplication.
- Improvements to the repository layer, including cancellation support and a simplified data source interface.
Setup Your Project
To use the Paging 3.0 library, add it to your app level build.gradle
file.
dependencies {
def paging_version = "3.0.0-alpha03"
implementation "androidx.paging:paging-runtime:$paging_version"
}
If you want to use RxJava
or LiveData
, you need to also include:
// optional - RxJava2 support
implementation "androidx.paging:paging-rxjava2:$paging_version"
// optional - Guava ListenableFuture support
implementation "androidx.paging:paging-guava:$paging_version"
Create a Data Source
Unlike the previous versions of Paging library, in Paging 3.0 we have to implement a PagingSource<Key, Value>
to define a data source. The PagingSource
takes two parameters a Key
and a Value
. The Key
parameter is the identifier of the data to be loaded such as page number and the Value
is the type of the data itself.
- Notice the overridden
load()
function is asuspend
function so we can make api requests here to get data from a network or a room database easily. - The
LoadParams
object holds the information about the load operation such askey
and page size. - If the api request is successful, then we will return the response data wrapped in a
LoadResult.Page
object along with the previous and next keys. - If the api request is unsuccessful then we will return the occurred exception wrapped in a
LoadResult.Error
object.
The figure below shows exactly how the load()
function recieves keys from the previous load and provides the keys for the next load.
Get the PagingData in ViewModel
Now we will create an instance of Pager
in our viewmodel to get a stream of data from the MoviePagingSource
that we just created.
- The
Pager
object calls theload()
method from theMoviePagingSource
object, providing it with theLoadParams
object and receiving theLoadResult
object in return. - We also have to provide configurations such as
pageSize
with thePagingConfig
object. - The
cachedIn(viewModelScope)
caches the data from theMoviePagingSource
to survive the screen orientation changes.
Display data in RecyclerView
First we have to create a RecyclerView
adapter class which extends from the PagingDataAdapter
. This is the same as a normal RecyclerView
adapter. The PagingDataAdapter
takes two parameters, the first one is the type of the data(which in our case is the Movie
object), and the second one is a RecyclerView.ViewHolder
.
Finally, in OnActivityCreated()
of our fragment, we can collect the data from PagingData
and then submit it into our MovieAdapter
.
The RecyclerView
list now displays data from the data source and automatically loads more data when we reach at the end of the list.
Display LoadState and Error messages
The Paging 3.0 library has support for displaying loading states and handling errors. The Paging library exposes the loading state for use in the UI through the LoadState
object.
- If the
LoadState
is aLoadState.NotLoading
object, then there is no active load operation and no errors. - If the
LoadState
is aLoadState.Loading
object, then there is an active load operation. - If the
LoadState
is aLoadState.Error
object, then there is an error.
We can attach a addLoadStateListener()
in our MovieAdapter
to listen for LoadState
updates.
In the next article, we learn how to create header or footers to show the loading state in the RecyclerView
itself, and then we will learn to create list separators.
Conclusion
The Paging 3.0 architectural components library is a major update over the previous versions of paging library, and it is completely rewritten from the previous versions of Paging library. It has complete support for the Kotlin coroutines
and other reactive streams such as RxJava
and LiveData
. It also has inbuilt error handling functionality and support for managing loading states which makes implementing paging in our app super easy.