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.

Vivek Singh
ProAndroidDev

--

Image on Jetpack Compose offficial docs

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.

MovieSource.kt

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.

MainViewModel.kt

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.

MovieList.kt
  • The MovieList() composable receives the Flow<PagingData<Movie>> from the ViewModel.
  • We need to convert the Flow<PagingData<Movie>> into LazyPagingItems<Movie> with the collectAsLazyPagingItems() extension function which collects the flow of paging data and converts it into lazy paging items.
  • The lazyMovieItems can then be passed into the items() extension function of the LazyListScope which provides a lamda with Movie as a parameter.
  • We can now display the Movie with the MovieItem() composable which is as follows:
MovieItem.kt

The LazyColumn() now displays the data from the MovieSource and loads more data when we reach at the end of the list.

A Jetpack Compose app loads data with Paging 3

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.

MovieList.kt
  • When the loadState.refresh is equal to LoadState.Loading which means when the data is loading for the first time, we can display a full screen CirclularProgressIndicator.
  • The loadState.append is for constituent loads so when it will be loading, we can show a loading item in the LazyColumn().
  • LazyPagingItems provides a retry() 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.

A Jetpack Compose app loads data With Paging 3

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.😀

--

--