<?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: Vitali Olshevski</title>
    <description>The latest articles on DEV Community by Vitali Olshevski (@olshevski).</description>
    <link>https://dev.to/olshevski</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%2F773825%2F80478357-fc78-4f70-bd3a-4e350d3d444d.jpg</url>
      <title>DEV Community: Vitali Olshevski</title>
      <link>https://dev.to/olshevski</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/olshevski"/>
    <language>en</language>
    <item>
      <title>Compose Navigation Reimagined</title>
      <dc:creator>Vitali Olshevski</dc:creator>
      <pubDate>Thu, 03 Feb 2022 19:02:37 +0000</pubDate>
      <link>https://dev.to/olshevski/compose-navigation-reimagined-ja</link>
      <guid>https://dev.to/olshevski/compose-navigation-reimagined-ja</guid>
      <description>&lt;p&gt;Hi there!&lt;/p&gt;

&lt;p&gt;Today I would like to share with you a small and sweet library I was meticulously crafting since December of the last year. It started as a simple proof-of-concept, but eventually evolved into something much more elaborate.&lt;/p&gt;

&lt;p&gt;Here I present to you the result of my work: &lt;a href="https://github.com/olshevski/compose-navigation-reimagined"&gt;Compose Navigation Reimagined&lt;/a&gt; - the navigation library built specifically for Android and Jetpack Compose.&lt;/p&gt;

&lt;h3&gt;
  
  
  But why?
&lt;/h3&gt;

&lt;p&gt;Ever since I started learning Compose and dug into the official &lt;a href="https://developer.android.com/jetpack/compose/navigation"&gt;Navigation Component&lt;/a&gt;, I was quite disappointed with the suggested way of handling navigation. The library has its fair share of flaws and redundancies. And I've already tried working around all its weirdnesses &lt;a href="https://github.com/olshevski/compose-safe-args"&gt;that one time&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But I knew that it could be done much better. Yes, "reinventing the wheel", you would say. But more wheels to choose from is always a benefit. Judge for yourself.&lt;/p&gt;

&lt;h3&gt;
  
  
  What can it do?
&lt;/h3&gt;

&lt;p&gt;Here is the list of the main features:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full type-safety&lt;/li&gt;
&lt;li&gt;State restoration&lt;/li&gt;
&lt;li&gt;Nested navigation with independent backstacks&lt;/li&gt;
&lt;li&gt;Own lifecycle, saved state and view models for every backstack entry&lt;/li&gt;
&lt;li&gt;Animated transitions&lt;/li&gt;
&lt;li&gt;Navigation logic may be easily moved to the ViewModel layer&lt;/li&gt;
&lt;li&gt;No builders, no obligatory superclasses for your composables&lt;/li&gt;
&lt;li&gt;May be used for managing dialogs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is pretty much everything the official library can do, and even more. Yes, there are no directional graphs and automatic deep-link handling, but that can be easily added if you need to. The main goal of the library is to allow developers to expand on the core functionality, rather than fight against its strict rules.&lt;/p&gt;

&lt;h3&gt;
  
  
  Show me the code
&lt;/h3&gt;

&lt;p&gt;Ok, first you define a set of destinations of an arbitrary type. The type must be writable to &lt;a href="https://developer.android.com/reference/android/os/Parcel"&gt;Parcel&lt;/a&gt; and &lt;a href="https://developer.android.com/reference/kotlin/androidx/compose/runtime/Stable"&gt;Stable&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Let's use a sealed class, as it is the most Kotlin way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;sealed&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Parcelable&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
    &lt;span class="kd"&gt;object&lt;/span&gt; &lt;span class="nc"&gt;First&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="nd"&gt;@Parcelize&lt;/span&gt;
    &lt;span class="kd"&gt;data class&lt;/span&gt; &lt;span class="nc"&gt;Third&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we create a composable with &lt;code&gt;NavController&lt;/code&gt; and &lt;code&gt;NavHost&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;NavHostScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;navController&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;rememberNavController&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;(&lt;/span&gt;
        &lt;span class="n"&gt;startDestination&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;First&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nc"&gt;NavBackHandler&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="nc"&gt;NavHost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;controller&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;screen&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
        &lt;span class="k"&gt;when&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;First&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"First screen"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Second&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"To Second screen"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Second&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Column&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Second screen: ${screen.id}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;navController&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;navigate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Third&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
                &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"To Third screen"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nc"&gt;Screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Third&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Third screen: ${screen.text}"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, &lt;code&gt;NavController&lt;/code&gt; is used for switching between screens, &lt;code&gt;NavBackHandler&lt;/code&gt; handles the back presses and &lt;code&gt;NavHost&lt;/code&gt; simply provides a composable corresponding to the latest destination in the backstack. As simple as that.&lt;/p&gt;

&lt;p&gt;For more details about the library, visit &lt;a href="https://github.com/olshevski/compose-navigation-reimagined"&gt;the github page of the project&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  The status of the library
&lt;/h3&gt;

&lt;p&gt;The library is currently in Beta, as I want to hear feedback and do minor fine-tuning of the API (if any at all).&lt;/p&gt;

&lt;p&gt;But for the most part, I consider it done and ready for some action.&lt;/p&gt;

&lt;p&gt;Anyways, I hope you like it and find it useful.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;And if you do, please bookmark/star the project and share it with your fellow developers. A little bit of promotion never hurts.&lt;/em&gt;&lt;/p&gt;

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