Infinite Lists With Paging 3 in Jetpack Compose
In this article you will learn how to do pagination with Paging 3 library in Jetpack Compose.

Previously there was no official support for paging in Jetpack Compose, but with the release of compose version 1.0.0-alpha06
, jetpack officially released the paging-compose
library which provides integration between compose and Paging 3 library.
As a quick recap from my original article on how to use Paging 3 library to display data in a RecyclerView
, paging is an efficient way to load small chunks of data at a time, and as soon as the user reach at the end of the list, more data will be loaded.
Code snippets in this article are taken from:
Setup Your Project
Add the required dependencies for paging in the app level build.gradle
file in a jetpack compose enabled project.
dependencies {
...
// Paging Compose
implementation "androidx.paging:paging-compose:1.0.0-alpha02"
}
Note: Both the paging-compose and jetpack compose are currently in alpha. So changes in both the api’s are expected which can be different as described in this article.
Create the Data Source
This is the same as creating the data source in paging 3 as described in the original article.
The data source can be the same for displaying the data in a RecyclerView
in the legacy view system or a declarative list in jetpack compose.
Once the data source is created, we will now create an instance of Pager
in our ViewModel. We can use .flow
on the Pager
object to get a stream of data as a Flow<PagingData<Movie>>
from the MovieSource
that we just created.
The Flow
will emit every time the Pager
loads new data from the MovieSource
.
Display Data In a List
We already created a Flow
of PagingData<Movie>
, now we must collect the flow and display the data into a list. In the legacy view system we had PagingDataAdapter
provided by the paging 3 library to display the PagingData
in a RecyclerView
.
In Jetpack Compose we have LazyColumn
and LazyRow
as a substitute for RecyclerView
to display a list of data. The paging-compose
library comes with extension functions on the LazyListScope
which will be used by the LazyColumn()
and LazyRow()
composables to display the PagingData
into a list.
- The
MovieList()
composable receives theFlow<PagingData<Movie>>
from the ViewModel. - We need to convert the
Flow<PagingData<Movie>>
intoLazyPagingItems<Movie>
with thecollectAsLazyPagingItems()
extension function which collects the flow of paging data and converts it into lazy paging items. - The
lazyMovieItems
can then be passed into theitems()
extension function of theLazyListScope
which provides a lamda withMovie
as a parameter. - We can now display the
Movie
with theMovieItem()
composable which is as follows:
The LazyColumn()
now displays the data from the MovieSource
and loads more data when we reach at the end of the list.

Displaying LoadStates and ErrorMessages
If you remember from the original article, the paging 3 library has built in support for displaying loading states and handling errors. The paging-compose
library exposes the loading state with LoadState
object which can be obtained from the LazyPagingItems
.
We can display different list items in the LazyColumn()
based on the LoadState
with the item{}
extension function which is almost the same as the items()
function we talked about in the previous section.
We can modify the MovieList()
composable from above to also display a CircularProgressIndicator
, or a error message and a retry button based on the loading state.
- When the
loadState.refresh
is equal toLoadState.Loading
which means when the data is loading for the first time, we can display a full screenCirclularProgressIndicator
. - The
loadState.append
is for constituent loads so when it will be loading, we can show a loading item in theLazyColumn()
. LazyPagingItems
provides aretry()
function to retry the load if there is an error.
Similarly, we can show error message and a retry button when the loadState.refresh
or loadState.append
is equal to LoadState.Error
.
The app now displays a loading progress bar or an error message with a retry button based on the loading state.

The complete source code of this application can be found in this repository.
Final Thoughts
Implementing paging can sometimes get tricky, fortunately for us it was made easy when jetpack released the Paging 3 library which has features such as support for Kotlin coroutines, Kotlin flow, loading states, handling errors.
Comparing compose to the RecyclerView
paging 3 approach we can see that the view system was quite a cumbersome process which involved writing boilerplate code such as adapters and viewholders. Reacting to the different load states by adding loadStateListeners
was also an exhaustive task.
The support for paging 3 in the jetpack compose has made the implementation of paging in an app super easy. We no longer need to create adapters, we can display different composables based on different load states easily. We can even make list with multiple view types with just little amount of declarative code.
References
That’s it, thank you all 🙏 for reading this article.😀