<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: kriticalflare</title>
    <description>The latest articles on DEV Community by kriticalflare (@kriticalflare).</description>
    <link>https://dev.to/kriticalflare</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F411153%2F8325e898-77e1-494e-a7be-f265f4642042.jpeg</url>
      <title>DEV Community: kriticalflare</title>
      <link>https://dev.to/kriticalflare</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/kriticalflare"/>
    <language>en</language>
    <item>
      <title>Implementing Paging in Jetpack Compose</title>
      <dc:creator>kriticalflare</dc:creator>
      <pubDate>Wed, 04 Nov 2020 16:44:47 +0000</pubDate>
      <link>https://dev.to/kriticalflare/implementing-paging-in-jetpack-compose-2hh7</link>
      <guid>https://dev.to/kriticalflare/implementing-paging-in-jetpack-compose-2hh7</guid>
      <description>&lt;p&gt;Jetpack Compose Alpha06 was recently released and along with it, came the new &lt;a href="https://developer.android.com/jetpack/androidx/releases/paging#paging_compose_version_100_2" rel="noopener noreferrer"&gt;paging-compose&lt;/a&gt; library. The library provides integration between the &lt;a href="https://developer.android.com/topic/libraries/architecture/paging/v3-overview" rel="noopener noreferrer"&gt;Paging 3.0&lt;/a&gt; library and Jetpack Compose.&lt;/p&gt;

&lt;p&gt;Both Paging and Jetpack Compose are in alpha rightnow so expect the API to have changes in near future. &lt;/p&gt;

&lt;p&gt;This article will be a short one focused more on integrating paging with compose rather than specifics of paging 3.0 itself.&lt;/p&gt;

&lt;p&gt;The code snippets used in this article are from &lt;br&gt;
 &lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kriticalflare" rel="noopener noreferrer"&gt;
        kriticalflare
      &lt;/a&gt; / &lt;a href="https://github.com/kriticalflare/Rick-Morty-Compose" rel="noopener noreferrer"&gt;
        Rick-Morty-Compose
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Android app using Jetpack Compose and Rick and Morty API
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
 
&lt;h2&gt;
  
  
  Adding the dependencies
&lt;/h2&gt;

&lt;p&gt;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.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/build.gradle


     def paging_compose_version = "1.0.0-alpha01"
     implementation "androidx.paging:paging-compose:$paging_compose_version"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Setting up the Data Source
&lt;/h2&gt;

&lt;p&gt;One can setup the paging data source for jetpack compose in the same fashion as one does for the legacy view based world.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;class CharactersPaging {

    fun getCharacters(): PagingSource&amp;lt;Int, Character&amp;gt; {
        return object : PagingSource&amp;lt;Int, Character&amp;gt;() {
            override suspend fun load(params: LoadParams&amp;lt;Int&amp;gt;): LoadResult&amp;lt;Int, Character&amp;gt; {
                val pageNumber = params.key ?: 0

                val charactersResponse = RickMortyClient.INSTANCE.getAllCharacters(page = pageNumber)
                val characters = charactersResponse.results

                val prevKey = if (pageNumber &amp;gt; 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
                )
            }
        }
    }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I have used the &lt;a href="https://rickandmortyapi.com/documentation" rel="noopener noreferrer"&gt;Rick And Morty&lt;/a&gt; API for this example. The API gives us an &lt;code&gt;Info&lt;/code&gt; object in response which provides information about the previous and next pages (if they exist).&lt;/p&gt;
&lt;h2&gt;
  
  
  Connecting the data source to the UI
&lt;/h2&gt;

&lt;p&gt;The library comes with special extension functions on the &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/foundation/lazy/LazyListScope#summary" rel="noopener noreferrer"&gt;LazyList Scope&lt;/a&gt; used by the lazy column and row composables which makes declarative lists very easy to create. &lt;/p&gt;

&lt;p&gt;We create a Pager which provides us a flow of PagingData backed by the data source we built earlier.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val charactersPaging = remember {
                CharactersPaging()
            }
val pager = remember {
                Pager(
                    PagingConfig(
                        pageSize = 20,
                        enablePlaceholders = true,
                    )
                ) {                  
                 charactersPaging.getCharacters()
                }
            }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This flow can then be converted to the &lt;a href="https://developer.android.com/reference/kotlin/androidx/paging/compose/LazyPagingItems" rel="noopener noreferrer"&gt;lazyPagingItems&lt;/a&gt; using the extensions from paging compose as follows.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val lazyPagingItems: LazyPagingItems&amp;lt;Character&amp;gt; = pager.flow.collectAsLazyPagingItems()
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;These lazyPagingItems can be then passed to the &lt;code&gt;items&lt;/code&gt; and &lt;code&gt;itemsIndexed&lt;/code&gt; &lt;a href="https://developer.android.com/reference/kotlin/androidx/paging/compose/package-summary.html#extension-functions-summary" rel="noopener noreferrer"&gt;extension methods&lt;/a&gt; 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.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import androidx.paging.compose.items
import androidx.paging.compose.itemsIndexed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Now in typical declarative ui fashion, we can emit different composables depending on different loadStates.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;LazyColumn{
                if (lazyPagingItems.loadState.refresh == LoadState.Loading) {
                    item {
                        Column(
                            modifier = Modifier.fillParentMaxSize(),
                            verticalArrangement = Arrangement.Center,
                            horizontalAlignment = Alignment.CenterHorizontally
                        ) {
                            CircularProgressIndicator()
                        }
                    }
                }

                itemsIndexed(lazyPagingItems) { index, item -&amp;gt;
                    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)
                        )
                    }
                }
          }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The final implementation
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@ExperimentalLazyDsl
@Composable
fun CharacterScreen(
    modifier: Modifier = Modifier.fillMaxSize(),
    onCharSelect: (Int) -&amp;gt; Unit
) {
    Surface {
        Box(
            modifier = modifier,
        ) {
            val charactersPaging = remember {
                CharactersPaging()
            }
            val pager = remember {
                Pager(
                    PagingConfig(
                        pageSize = 20,
                        enablePlaceholders = true,
                    )
                ) {                  charactersPaging.getCharacters()
                }
            }

            val lazyPagingItems: LazyPagingItems&amp;lt;Character&amp;gt; = 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 -&amp;gt;
                    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)
                        )
                    }
                }
            }
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;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  &lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/kriticalflare" rel="noopener noreferrer"&gt;
        kriticalflare
      &lt;/a&gt; / &lt;a href="https://github.com/kriticalflare/Rick-Morty-Compose" rel="noopener noreferrer"&gt;
        Rick-Morty-Compose
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Android app using Jetpack Compose and Rick and Morty API
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Rick-Morty-Compose&lt;/h1&gt;

&lt;/div&gt;

&lt;p&gt;Android app using Jetpack Compose and Rick and Morty API built using&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Compose&lt;/li&gt;
&lt;li&gt;Retrofit&lt;/li&gt;
&lt;li&gt;ViewModel&lt;/li&gt;
&lt;li&gt;Coroutines&lt;/li&gt;
&lt;li&gt;Moshi&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/chrisbanes/accompanist" rel="noopener noreferrer"&gt;Accompanist&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://rickandmortyapi.com" rel="nofollow noopener noreferrer"&gt;Rick And Morty API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/jetpack/compose/navigation" rel="nofollow noopener noreferrer"&gt;Navigation Component Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/jetpack/androidx/releases/paging#paging_compose_version_100_2" rel="nofollow noopener noreferrer"&gt;Paging Compose&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;/div&gt;
&lt;br&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/kriticalflare/Rick-Morty-Compose" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;
 

&lt;p&gt;Thank you for reading! You can get in touch with me here on &lt;a href="//dev.to/kriticalfare"&gt;Dev&lt;/a&gt; , &lt;a href="//github.com/kriticalflare"&gt;Github&lt;/a&gt; or &lt;a href="https://www.linkedin.com/in/krithik-suvarna/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt;&lt;/p&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>jetpackcompose</category>
    </item>
  </channel>
</rss>
