Jetpack Compose Alpha06 was recently released and along with it, came the new paging-compose library. The library provides integration between the Paging 3.0 library and Jetpack Compose.
Both Paging and Jetpack Compose are in alpha rightnow so expect the API to have changes in near future.
This article will be a short one focused more on integrating paging with compose rather than specifics of paging 3.0 itself.
The code snippets used in this article are from
kriticalflare / Rick-Morty-Compose
Android app using Jetpack Compose and Rick and Morty API
Adding the dependencies
Add the following dependencies to an existing Jetpack Compose project or create a new project using the compose template from the latest Android Studio Canary.
app/build.gradle
def paging_compose_version = "1.0.0-alpha01"
implementation "androidx.paging:paging-compose:$paging_compose_version"
Setting up the Data Source
One can setup the paging data source for jetpack compose in the same fashion as one does for the legacy view based world.
class CharactersPaging {
fun getCharacters(): PagingSource<Int, Character> {
return object : PagingSource<Int, Character>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Character> {
val pageNumber = params.key ?: 0
val charactersResponse = RickMortyClient.INSTANCE.getAllCharacters(page = pageNumber)
val characters = charactersResponse.results
val prevKey = if (pageNumber > 0) pageNumber - 1 else null
val nextKey = if (charactersResponse.info.next != null) pageNumber + 1 else null
return LoadResult.Page(
data = characters,
prevKey = prevKey,
nextKey = nextKey
)
}
}
}
}
I have used the Rick And Morty API for this example. The API gives us an Info
object in response which provides information about the previous and next pages (if they exist).
Connecting the data source to the UI
The library comes with special extension functions on the LazyList Scope used by the lazy column and row composables which makes declarative lists very easy to create.
We create a Pager which provides us a flow of PagingData backed by the data source we built earlier.
val charactersPaging = remember {
CharactersPaging()
}
val pager = remember {
Pager(
PagingConfig(
pageSize = 20,
enablePlaceholders = true,
)
) {
charactersPaging.getCharacters()
}
}
This flow can then be converted to the lazyPagingItems using the extensions from paging compose as follows.
val lazyPagingItems: LazyPagingItems<Character> = pager.flow.collectAsLazyPagingItems()
These lazyPagingItems can be then passed to the items
and itemsIndexed
extension methods on the LazyList Scope. Android Studio has trouble importing the correct extension methods in this case, so make sure to add these imports manually if you face any issues.
import androidx.paging.compose.items
import androidx.paging.compose.itemsIndexed
Now in typical declarative ui fashion, we can emit different composables depending on different loadStates.
LazyColumn{
if (lazyPagingItems.loadState.refresh == LoadState.Loading) {
item {
Column(
modifier = Modifier.fillParentMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}
}
itemsIndexed(lazyPagingItems) { index, item ->
if (item != null) {
CharacterItem(
modifier = Modifier.padding(8.dp),
character = item,
onClick = onCharSelect
)
}
}
if (lazyPagingItems.loadState.append == LoadState.Loading) {
item {
CircularProgressIndicator(
modifier = Modifier.fillMaxWidth()
.wrapContentWidth(Alignment.CenterHorizontally)
)
}
}
}
The final implementation
@ExperimentalLazyDsl
@Composable
fun CharacterScreen(
modifier: Modifier = Modifier.fillMaxSize(),
onCharSelect: (Int) -> Unit
) {
Surface {
Box(
modifier = modifier,
) {
val charactersPaging = remember {
CharactersPaging()
}
val pager = remember {
Pager(
PagingConfig(
pageSize = 20,
enablePlaceholders = true,
)
) { charactersPaging.getCharacters()
}
}
val lazyPagingItems: LazyPagingItems<Character> = pager.flow.collectAsLazyPagingItems()
LazyColumn{
if (lazyPagingItems.loadState.refresh == LoadState.Loading) {
item {
Column(
modifier = Modifier.fillParentMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
}
}
}
itemsIndexed(lazyPagingItems) { index, item ->
if (item != null) {
CharacterItem(
modifier = Modifier.padding(8.dp),
character = item,
onClick = onCharSelect
)
}
}
if (lazyPagingItems.loadState.append == LoadState.Loading) {
item {
CircularProgressIndicator(
modifier = Modifier.fillMaxWidth()
.wrapContentWidth(Alignment.CenterHorizontally)
)
}
}
}
}
}
}
Its pretty clear that Jetpack Compose makes implementation of Paging 3.0 much simpler than the legacy view system. You can check out the project used in this article for more examples integrating Paging, Navigation Component, Edge to Edge UI and much more
kriticalflare / Rick-Morty-Compose
Android app using Jetpack Compose and Rick and Morty API
Rick-Morty-Compose
Android app using Jetpack Compose and Rick and Morty API built using
- Compose
- Retrofit
- ViewModel
- Coroutines
- Moshi
- Accompanist
- Rick And Morty API
- Navigation Component Compose
- Paging Compose
Thank you for reading! You can get in touch with me here on Dev , Github or Linkedin
Top comments (0)