<?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: Patryk Kosieradzki</title>
    <description>The latest articles on DEV Community by Patryk Kosieradzki (@patrykkosieradzki).</description>
    <link>https://dev.to/patrykkosieradzki</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%2F821445%2Fcfbd2531-77d7-4a63-bc74-d68ef2713b9e.jpg</url>
      <title>DEV Community: Patryk Kosieradzki</title>
      <link>https://dev.to/patrykkosieradzki</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/patrykkosieradzki"/>
    <language>en</language>
    <item>
      <title>Dagger/Hilt vs Koin for Jetpack Compose apps</title>
      <dc:creator>Patryk Kosieradzki</dc:creator>
      <pubDate>Mon, 14 Mar 2022 22:03:15 +0000</pubDate>
      <link>https://dev.to/patrykkosieradzki/daggerhilt-vs-koin-for-jetpack-compose-apps-jci</link>
      <guid>https://dev.to/patrykkosieradzki/daggerhilt-vs-koin-for-jetpack-compose-apps-jci</guid>
      <description>&lt;p&gt;See the original article &lt;a href="https://patrykkosieradzki.com/dagger-hilt-vs-koin-for-jetpack-compose-apps/"&gt;on my website&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;Ahh, here we go again. The eternal struggle between Dagger/Hilt and Koin. I expect a lot of arguments again in the comments about which one is better, but don’t worry guys, this article was created only to show you the main differences between them. Both of them are great, so you have to choose which one you want to use on your own, BUT I hope I’ll make this choice a little easier for you by showing you their advantages and disadvantages for Jetpack Compose apps!&lt;/p&gt;

&lt;p&gt;For the purposes of this article I’m gonna assume that you already know what Dependency Injection is and what are the main differences between Dagger/Hilt and Koin, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code generation VS no code generation&lt;/li&gt;
&lt;li&gt;Impact on build time VS impact on runtime and injection time&lt;/li&gt;
&lt;li&gt;And obviously Hilt is recommended and maintained by Google, while Koin is not. Of course, Google does not say that Koin is bad and to use what you think fits better to your project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here’s Manuel Vivo’s opinion about Koin, for example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Google recommends Hilt for Android apps but that’s just a recommendation! Use what you think it’s good for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Source: &lt;a href="https://medium.com/@manuelvicnt/hi-i-think-koin-is-a-great-library-as-well-use-what-you-think-fits-better-to-your-project-885b4992a5b2"&gt;medium.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If none of this sounds familiar then you should probably stop reading for a moment and first figure out what Dependency Injection, Dagger, Hilt and Koin are before continuing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Let’s roll
&lt;/h2&gt;

&lt;p&gt;Okay, so now let’s compare Dagger/Hilt and Koin.&lt;/p&gt;

&lt;p&gt;To best present the PROS and CONS of each of these tools, I will consider two cases where you can use Jetpack Compose to write Android Apps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first case — when your app is written in pure Jetpack Compose, that is, without using Fragments, so you’re probably using navigation-compose library.&lt;/li&gt;
&lt;li&gt;And the second case — when you use Fragments and ComposeView (Interoperability), which in my opinion is the best choice (at least for now), mostly because of the bad Navigation-Compose API and lack of type safety. This is quite a big and controversial topic, but hey, this is what I like the most 😎&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;Be sure to check &lt;a href="https://patrykkosieradzki.medium.com/why-using-navigation-compose-in-your-jetpack-compose-app-is-a-bad-idea-2b16e8751d89"&gt;my article about this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Also, if you’re a Polish speaker, you can listen to my “Android Talks” Podcast episode about it: &lt;a href="https://androidtalks.buzzsprout.com/1820265/9680778"&gt;https://androidtalks.buzzsprout.com/1820265/9680778&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  PROS of using Hilt in your app
&lt;/h2&gt;

&lt;p&gt;So what are some of the good things about Hilt?&lt;/p&gt;

&lt;h2&gt;
  
  
  Jetpack and Support
&lt;/h2&gt;

&lt;p&gt;First of all, Hilt is a part of Jetpack and currently Google recommends that you use it in your Android Apps. Of course, that’s not a big deal, but I must say it’s really nice that Google created it, as some of you may know, using Dagger was not always as nice and enjoyable as we would like it to be — especially for programmers who were just starting to learn Dependency Injection in Android.&lt;/p&gt;

&lt;h2&gt;
  
  
  Easier to implement than Dagger
&lt;/h2&gt;

&lt;p&gt;Second thing, like I’ve just mentioned, if you were using Dagger before and you liked it, you’re gonna LOVE using Hilt!&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;New annotations like @AndroidEntryPoint or @HiltViewModel make it much easier to manage DI code in your Android classes.&lt;/li&gt;
&lt;li&gt;Creating modules is now less complicated with Generated components for Android classes like SingletonComponent, ViewModelComponent, etc.&lt;/li&gt;
&lt;li&gt;And much more! Check out everything &lt;a href="https://developer.android.com/training/dependency-injection/hilt-android"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Compile time errors
&lt;/h2&gt;

&lt;p&gt;Dagger and Hilt are compile-time dependency injection frameworks. It means that if we accidentally forget to provide some dependency or we mess something up the build is gonna fail and our app won’t run at all.&lt;/p&gt;

&lt;p&gt;Koin will behave differently in this situation. As you know Koin does not generate any code, so if we mess something up with DI the project will build anyway, but it will crash at start or later on some specific screen.&lt;/p&gt;

&lt;p&gt;The developer would have to check whether the dependencies in this specific part of the app are working well and the app does not crash. Dagger/Hilt is much safer to use in that case.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;

&lt;p&gt;The next big thing is TESTING. For sure, writing Unit, UI, E2E, etc. tests was already possible with Dagger, BUT what we get from Hilt now is much, much more! Forget about complicated tests with Dagger. Now you have HiltAndroidRule to manage the component’s state and to inject different dependencies to tests easier.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@HiltAndroidTest
class SettingsActivityTest {

  @get:Rule
  var hiltRule = HiltAndroidRule(this)

  // UI tests here.
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can easily replace and mock dependencies or even the whole modules on the fly. Also, you can launch your Fragments (if you’re using them) in a special test container launchFragmentInHiltContainer. If you’re not using Fragments or you want to test only the Composable, you can easily do that with ComposeTestRule, where you can pass your ViewModel and other dependencies directly to the Composable Function (example on my Github). It is also possible to automatically mock every ViewModel in your UI tests, so the test setup is only a few lines of code 😉.&lt;/p&gt;

&lt;h2&gt;
  
  
  Process death
&lt;/h2&gt;

&lt;p&gt;Securing your app against process death is also a lot easier with Hilt. You can simply inject SavedStateHandle to the ViewModel (which is just a fancy StateHandle map) to store and restore data that needs to be saved in case of process death.&lt;/p&gt;

&lt;h2&gt;
  
  
  CONS of using Hilt
&lt;/h2&gt;

&lt;p&gt;Is Hilt flawless? Let’s find out 🤔&lt;/p&gt;

&lt;h2&gt;
  
  
  Slower build time
&lt;/h2&gt;

&lt;p&gt;As most of you probably know Hilt generates some files during build time, which means that the bigger the app and the more modules, components and dependencies you have, the longer your build time is gonna get 🐢.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sometimes you have to write Dagger code
&lt;/h2&gt;

&lt;p&gt;While using Hilt is much easier than it was with Dagger, sometimes you will still need use Dagger code in your app. If you want to create separate android modules per features in your app then you’ll have to write some of your code in the old fashioned way with Dagger. First, you have to create a custom EntryPoint module, combine it inside the component’s builder and then programatically inject it into the Activity or Fragment that hosts the feature. You can read more about it here.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can’t inject anything other than ViewModel into Composables (at least for now)
&lt;/h2&gt;

&lt;p&gt;One of the major flaws for me is the fact that if you’re writing a Compose only app without Fragments you can’t inject dependencies into the Composables, other than ViewModels.&lt;/p&gt;

&lt;p&gt;Probably a lot of you are wondering now, why would you even need something like that at all?&lt;/p&gt;

&lt;p&gt;Well, first of all this is certainly a loss of functionality, because before Compose we were able to inject dependencies into Fragments, Activities, etc. and now as Fragments were “replaced” by Composables you’d expect that this feature should be still there, right?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;So can you give me some examples when it would be useful?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Sure. Here are a few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;To delegate UI logic/work to other classes from Composables, so your code is more reusable and concise.&lt;/li&gt;
&lt;li&gt;To render UI differently, based on data you get from specific dependencies like AppConfig or something else that doesn’t really make sense to put in the ViewModel’s logic (because there’s no logic). Example: I want to display additional text in the Composable if I’m currently in DEBUG mode. I have the isDebug: Boolean value in AppConfig singleton.&lt;/li&gt;
&lt;li&gt;Another example: Let’s say you need to have multiple Coil ImageLoaders and you want to use them in some of your Composables. You can’t inject them directly into the Composable, so you’d probably have to pass them from the Activity to the NavGraph and then either pass it through Composable params or use CompositionLocalProvider.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;Can this problem be solved easily? Yes.&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;As I told you before, I prefer using Compose with Fragments and this is another reason why I still use them. You can just inject dependencies inside Fragments and then pass them along to Composables.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;&lt;strong&gt;And what if I want to pass the dependency really deep into the Composable tree?&lt;/strong&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Well, first think twice if you really need to pass it. If the answer is still yes then you can either pass the variable through each Composable down the tree or you can think about using CompositionLocalProvider. This requires you to write additional code, but it’s still an option.&lt;/p&gt;




&lt;h2&gt;
  
  
  And how does this relate to Koin?
&lt;/h2&gt;

&lt;p&gt;Let’s star with PROs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Way easier to use than Dagger and Hilt
&lt;/h2&gt;

&lt;p&gt;First of all, Koin is definitely much simpler to use and to learn than Dagger or Hilt. It can be a good choice for novice programmers that want to learn Dependency Injection.&lt;/p&gt;

&lt;h2&gt;
  
  
  You can inject dependencies into Composables
&lt;/h2&gt;

&lt;p&gt;Unlike Dagger or Hilt, Koin allows us to inject dependencies into Composables.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Composable
fun SomeComposable(myService: MyService = get()) {
   // ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solves the problem I’ve mentioned before and is really nice to have when we don’t use Fragments.&lt;/p&gt;

&lt;h2&gt;
  
  
  More informative error logs
&lt;/h2&gt;

&lt;p&gt;If you used Dagger or Hilt before (especially Dagger) you may have noticed that they don’t give much info in the logs about errors that occur and you often have to guess and figure out what is really wrong.&lt;/p&gt;

&lt;p&gt;For example, in some cases Hilt would just tell you&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[Hilt]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and that’s all.&lt;/p&gt;

&lt;p&gt;Of course over time these problems were fixed and you’ll see more info now, but still Koin wins this fight and has more informative logs when errors happen.&lt;/p&gt;

&lt;h2&gt;
  
  
  No code generation
&lt;/h2&gt;

&lt;p&gt;Koin won’t generate any code at all. This means that your build times will be quicker 🏃&lt;/p&gt;

&lt;h2&gt;
  
  
  CONS
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Much more DI code, especially get(), get(), get()… get()
&lt;/h2&gt;

&lt;p&gt;As I mentioned before, Koin is much easier to implement, but it comes with a price — much more code. Every singleton, factory, viewModel, etc. you want to inject you have to add to your modules first.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val appModule = module {
   single { DogRepository(get()) } 

   factory { GetDogUseCase(get()) }
   viewModel {
      DogDetailsViewModel(get())
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So if you have a lot of arguments in your dependencies your modules could end up like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;val appModule = module {
   single { 
      DogRepository(get(), get(), get(), get(), get())
   } 

   factory { 
      GetDogUseCase(
         repo = get()
         cacheRepo = get(),
         service = get(),
         somethingElse = get()
      ) 
   }
   viewModel {
      DogDetailsViewModel(
         imagine = get(),
         a = get(),
         lot = get(),
         of = get(),
         dependencies = get(),
         here = get()
      )
   }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And this is only one ViewModel and one Repo / UseCase. Imagine how bad it will look in a bigger app…&lt;/p&gt;

&lt;h2&gt;
  
  
  Issues with SavedStateHandle when not using Fragments
&lt;/h2&gt;

&lt;p&gt;Currently it’s not possible to inject SavedStateHandle to your ViewModels if you don’t use Fragments and inject your viewmodels straight to the Composables. If you try to do that you’ll get an error. This should be fixed soon, but it is something you have to consider if you want to preserve screen state in case of process death.&lt;/p&gt;

&lt;h2&gt;
  
  
  Impact on runtime performance
&lt;/h2&gt;

&lt;p&gt;As I mentioned before Dagger/Hilt has a significant impact on build time due to code generation. On the other hand Koin also affects time, but not build, but runtime. Koin has slightly worse runtime performance, because it resolves dependencies at runtime.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--LjUbPcKQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0zcyncix3sgnrlmxqmj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--LjUbPcKQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r0zcyncix3sgnrlmxqmj.png" alt="Source: https://github.com/Sloy/android-dependency-injection-performance" width="554" height="311"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can find all of the results &lt;a href="https://github.com/Sloy/android-dependency-injection-performance"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So which DI should you choose to use? You have to decide yourself. I must admit I’m not a huge fan of Dagger (sorry Dagger lovers), but I would still recommend learning it.&lt;/p&gt;

&lt;p&gt;At the end of the day it’s not about which one is better but which one allows you to write clean code that is easy to test and maintain. I used all of them (Dagger, Hilt, Koin) in a few projects before and I think all of them (especially Hilt and Koin) match this criteria.&lt;/p&gt;




&lt;h2&gt;
  
  
  Check out my other articles:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://patrykkosieradzki.medium.com/why-using-navigation-compose-in-your-jetpack-compose-app-is-a-bad-idea-2b16e8751d89"&gt;Why using Navigation-Compose in your Jetpack Compose app is a bad idea&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://proandroiddev.com/livedata-vs-sharedflow-and-stateflow-in-mvvm-and-mvi-architecture-57aad108816d"&gt;LiveData vs SharedFlow and StateFlow in MVVM and MVI Architecture&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://proandroiddev.com/easy-ui-and-screenshot-testing-on-android-2b138f6d1eb8"&gt;Easy UI And Screenshot Testing On Android&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>jetpackcompose</category>
      <category>hilt</category>
    </item>
    <item>
      <title>Why using Navigation-Compose in your Jetpack Compose app is a bad idea</title>
      <dc:creator>Patryk Kosieradzki</dc:creator>
      <pubDate>Tue, 01 Mar 2022 23:03:11 +0000</pubDate>
      <link>https://dev.to/patrykkosieradzki/why-using-navigation-compose-in-your-jetpack-compose-app-is-a-bad-idea-ll8</link>
      <guid>https://dev.to/patrykkosieradzki/why-using-navigation-compose-in-your-jetpack-compose-app-is-a-bad-idea-ll8</guid>
      <description>&lt;p&gt;See the original article on Medium:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag__link"&gt;
  &lt;a href="https://medium.com/@patrykkosieradzki/why-using-navigation-compose-in-your-jetpack-compose-app-is-a-bad-idea-2b16e8751d89" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__pic"&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yMfeX1OT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://miro.medium.com/fit/c/96/96/1%2AFuJjHidT38UmTvBK28dyjw.jpeg" alt="Patryk Kosieradzki"&gt;
    &lt;/div&gt;
  &lt;/a&gt;
  &lt;a href="https://medium.com/@patrykkosieradzki/why-using-navigation-compose-in-your-jetpack-compose-app-is-a-bad-idea-2b16e8751d89" class="ltag__link__link"&gt;
    &lt;div class="ltag__link__content"&gt;
      &lt;h2&gt;Why using Navigation-Compose in your Jetpack Compose app is a bad idea | by Patryk Kosieradzki | Feb, 2022 | Medium&lt;/h2&gt;
      &lt;h3&gt;Patryk Kosieradzki ・ &lt;time&gt;Feb 14, 2022&lt;/time&gt; ・ 
      &lt;div class="ltag__link__servicename"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hnDHPsJs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/medium-f709f79cf29704f9f4c2a83f950b2964e95007a3e311b77f686915c71574fef2.svg" alt="Medium Logo"&gt;
        Medium
      &lt;/div&gt;
    &lt;/h3&gt;
&lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;


&lt;p&gt;And other articles about Android on my website:&lt;br&gt;
&lt;a href="https://patrykkosieradzki.com"&gt;https://patrykkosieradzki.com&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;If you’re reading this article, you’re probably thinking:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;“Hmm I wonder what to use to navigate in my Jetpack Compose app. Should I use navigation-compose as sugested by Google or stick with Fragments and use Compose only for rendering views?”&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this article, I’m going to talk about my experience with both Navigation-Compose and Fragments in a Jetpack Compose app. You will learn which approach is better (in my opinion) and what obstacles may await you by using each of them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Podcast!
&lt;/h2&gt;

&lt;p&gt;If you’re a Polish speaker, you can listen to a podcast I’ve made about this topic:&lt;br&gt;
&lt;a href="https://www.buzzsprout.com/1820265/9680778"&gt;https://www.buzzsprout.com/1820265/9680778&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Let’s start
&lt;/h2&gt;

&lt;p&gt;If you Google &lt;em&gt;“Jetpack Compose Navigation”&lt;/em&gt; you will probably see the Navigation-Compose library as one of the first results. Google describes it as a new navigation component that supports apps written in Compose and claims &lt;strong&gt;that thanks to it we can navigate between composables while taking advantage of the Navigation component’s infrastructure and features.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Sounds perfect, but is it? We should talk about what the new navigation looks like…&lt;/p&gt;

&lt;p&gt;Google really wanted to create a Framework that would be able to manage lifecycles, navigation and everything around it while eliminating the need to use Fragments. They came up with the idea to create a navigation graph as Composable (&lt;strong&gt;NavHost&lt;/strong&gt;) instead of an XML file, where we can define routes to which the application can navigate. In fact, if you look closely, Fragments are replaced by navBackstackEntry in this way. Unfortunately, it doesn’t work very well and there are a lot of issues with it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Route paths
&lt;/h2&gt;

&lt;p&gt;First of all — route paths.&lt;/p&gt;

&lt;p&gt;Google probably envied Flutter, React and other similar Frameworks and thought that the best solution for Android would be to define screen routes as in a web app — despite the fact that we create mobile applications, not web ones, right?&lt;/p&gt;

&lt;p&gt;What does this mean for us?&lt;/p&gt;

&lt;p&gt;This means that each route looks like an URL ending, e.g.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/users — for the user list screen&lt;/li&gt;
&lt;li&gt;/users/2 — for the detail screen for user with id = 2.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;From now on, the developer must maintain the order of the paths and their parts, remember them and their params, or create constants for individual screens, which already means that we have a lot more work to start than before.&lt;/p&gt;

&lt;p&gt;What comes next is even more confusing.&lt;/p&gt;
&lt;h2&gt;
  
  
  Navigation arguments
&lt;/h2&gt;

&lt;p&gt;Earlier, using Fragments and Safe Args, we could define in XML what arguments a given Fragment takes. When creating an action from one screen to another, we had an automatically generated code that asked us for arguments of the correct type and packed them into the &lt;strong&gt;Bundle&lt;/strong&gt;. Next, to extract these arguments in the target Fragment, we can use the &lt;strong&gt;by navArgs()&lt;/strong&gt; delegate for example, which will do it for us automatically.&lt;/p&gt;

&lt;p&gt;We were able to pass a lot of different types as parameters, such as Int, String, Boolean, etc. but also custom ones, such as Enums, Serializables and Parcelables. The full list of supported types can be found &lt;strong&gt;&lt;u&gt;&lt;a href="https://developer.android.com/guide/navigation/navigation-pass-data#supported_argument_types"&gt;here&lt;/a&gt;&lt;/u&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Is it just as convenient in navigation compose? &lt;strong&gt;NOT AT ALL&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Arguments can be passed only in the URL path of a given route, for example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Path params
&lt;em&gt;&lt;strong&gt;/users/{arg1}/details/{arg2}&lt;/strong&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;li&gt;Or to make it even more complicated, you can also pass query params and optional parameters after the question mark
&lt;em&gt;&lt;strong&gt;/users/{arg1}/details?{arg2}={arg2_value}&amp;amp;{arg3}={arg3_value}&lt;/strong&gt;&lt;/em&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Oh, and don’t forget that for each destination and param that you want to use, &lt;strong&gt;YOU&lt;/strong&gt; are responsible for all of the type safety. Compose navigation is not going to tell you that you mistook an Int param as a String. It will just crash the app.&lt;/p&gt;

&lt;p&gt;Each param has to be declared in composable in the NavHost:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And also extracted with a proper type later:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;So now, not only that the programmer has to manage all routes himself, he also has to remember what arguments are taken by a particular screen and what are the keys and data types of parameters and their order.&lt;/p&gt;

&lt;p&gt;Will you get the errors at compile time that you messed something up? Nope. You will get an error or an app crash only while the app is running.&lt;/p&gt;

&lt;h2&gt;
  
  
  Everything is a String
&lt;/h2&gt;

&lt;p&gt;Also, don’t forget that since the screen route is like an url, each parameter must be passed anyway as a String and &lt;strong&gt;must be encoded&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s say we want to pass this String as a param:&lt;br&gt;
&lt;code&gt;val urlParam = "https://translate.google.com/?hl=en&amp;amp;tab=TT"&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;To navigate with it we have to write this:&lt;br&gt;
&lt;code&gt;navController.navigate("path/arg=${URLEncoder.encode(urlParam)}")&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;And then receive it like this:&lt;br&gt;
&lt;code&gt;URLEncoder.decode(bundle.getString("arg_key"))&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Even better, if you use &lt;strong&gt;URLEncoder.encode(…)&lt;/strong&gt; over a String that contains a &lt;strong&gt;‘\n’&lt;/strong&gt; character, it will crash because of the ‘%0A’, so the only way to make it work is to use &lt;strong&gt;Base64&lt;/strong&gt; encoding first.&lt;/p&gt;

&lt;p&gt;This makes the Navigation-Compose API completely NON type safe.&lt;/p&gt;
&lt;h2&gt;
  
  
  What about Enums, Serializables and Parcelables?
&lt;/h2&gt;

&lt;p&gt;Like I’ve mentioned before, any argument we want to pass, regardless of type, has to be converted to a String in order to add it to the path.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enums&lt;/strong&gt;&lt;br&gt;
Compose navigation won’t let you pass &lt;strong&gt;Enums&lt;/strong&gt; as params, but this can be done differently. In theory, we can convert it into a String, and call the valueOf method on the target screen to find the value in the enum that we previously passed as String.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Parcelables and Serializables&lt;/strong&gt;&lt;br&gt;
This is where the fun begins. Passing &lt;strong&gt;Serializable&lt;/strong&gt; and &lt;strong&gt;Parcelable&lt;/strong&gt; as a navigation param in Compose-Navigation is not supported too.&lt;/p&gt;

&lt;p&gt;I see a lot of people on the Internet saying that it is possible to get into the &lt;strong&gt;backStackEntry&lt;/strong&gt; arguments and &lt;strong&gt;manually&lt;/strong&gt; pass the object there that extends &lt;strong&gt;Serializable&lt;/strong&gt; or &lt;strong&gt;Parcelable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;HOWEVER&lt;br&gt;
This is just a hack that Google does not recommend and does not give any guarantee that this will work.&lt;/p&gt;

&lt;p&gt;Personally, I have had a lot of situations where passing arguments in this way caused the app to crash.&lt;/p&gt;

&lt;p&gt;Don’t believe me? Just go here and read:&lt;br&gt;
&lt;strong&gt;&lt;a href="https://issuetracker.google.com/issues/182194894"&gt;https://issuetracker.google.com/issues/182194894&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is there anything we can do?&lt;/strong&gt;&lt;br&gt;
Well, theoretically… yeah. We could convert our &lt;strong&gt;Serializable&lt;/strong&gt; or &lt;strong&gt;Parcelable&lt;/strong&gt; object to &lt;strong&gt;JSON&lt;/strong&gt; and pass it as a String. I feel sorry for anyone who would like to pass params this way. This is a way to do it, but it’s so stupid and brings so much unnecessary boilerplate and complexity that I won’t even consider using it.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;UPDATE!&lt;/strong&gt;&lt;br&gt;
Since Compose version 1.0.3 and NavigationX 2.4.0-alpha10 we are now able to create a custom NavType:&lt;/p&gt;

&lt;p&gt;Let’s say you have a class like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;You can define the NavType like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;And use it:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;This seems better than what we had before &lt;strong&gt;BUT&lt;/strong&gt; still requires us to use JSON inside. Also imagine creating a new custom &lt;strong&gt;NavType&lt;/strong&gt; every time you want to pass a Parcelable. This just adds more boilerplate code to our app. Moreover there is &lt;strong&gt;no mention&lt;/strong&gt; in the documentation from Google that this solution will work with Compose-Navigation too.&lt;/p&gt;

&lt;h2&gt;
  
  
  BUT WHY?
&lt;/h2&gt;

&lt;p&gt;And now the main question arises — why?&lt;/p&gt;

&lt;p&gt;Why is Navigation-Compose like that? Why doesn’t it support Serializables, Parcelables and why does it have so many issues?&lt;/p&gt;

&lt;p&gt;It is very possible that Google wants to encourage developers to pass only id of the object and not the static copy of it. It would make sense if, for example, we were operating on the Room database and observing the data using Flow. For example, if something in the meantime changed this data, then the user would automatically see the current values on the screen.&lt;/p&gt;

&lt;p&gt;Indeed, maybe in a few cases like this, it would make sense. Unfortunately, there are often situations in which we want to consciously pass a static object, or at least some part of it so that the user immediately sees the data on the screen. After that, we could load some details in the background or simply check if the data is up-to-date.&lt;/p&gt;

&lt;h2&gt;
  
  
  Just use Fragments
&lt;/h2&gt;

&lt;p&gt;Okay, then how should I use Compose to avoid these problems? The answer is simple. Use Fragments and old navigation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Reasons why you should still use Fragments&lt;/strong&gt;&lt;br&gt;
You can use whatever you want: &lt;strong&gt;XML&lt;/strong&gt;, &lt;strong&gt;Compose&lt;/strong&gt;, you choose. The easiest way is to add &lt;strong&gt;ComposeView&lt;/strong&gt; to the &lt;strong&gt;Fragment&lt;/strong&gt; view and set &lt;strong&gt;Composable&lt;/strong&gt; of the given &lt;strong&gt;Fragment&lt;/strong&gt; there.&lt;/p&gt;

&lt;p&gt;Not a fan of LaunchedEffect, DisposableEffect and so on? You don’t have to use them as you can write some code the old way, just like it was in Fragments.&lt;/p&gt;

&lt;p&gt;Depending on what DI Framework you are using, you may also run into some issues with SavedStateHandle if you use Navigation-Compose.&lt;br&gt;
In my current project, we are using Koin and unfortunately SavedStateHandle cannot be injected into the ViewModel in the new navigation. This problem, of course, has to be fixed by Koin Team, but for now, it disappears if you use Fragments and inject the ViewModel using by viewModel() delegate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Of course, Fragments aren’t perfect. What issues with them should you consider in this case?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;First of all, you are using Fragments. This may seem funny at first, but some people don’t like them, for example Jake Wharton. In short, he says you can use Fragments, but the backstack is a nightmare.&lt;/p&gt;

&lt;p&gt;You have a little more code. After all, for each screen, you have to write both &lt;strong&gt;Fragment&lt;/strong&gt; and &lt;strong&gt;Composable&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Another thing is that you have two lifecycles that you need to manage — &lt;strong&gt;Fragment&lt;/strong&gt; and &lt;strong&gt;Composable&lt;/strong&gt; lifecycle. This may seem problematic at first, but fortunately, there is a quick way to deal with it. Just use the &lt;strong&gt;setViewCompositionStrategy&lt;/strong&gt; method on a &lt;strong&gt;ComposeView&lt;/strong&gt; and set how the &lt;strong&gt;Composable’s&lt;/strong&gt; lifecycle should behave in relation to the &lt;strong&gt;Fragment’s&lt;/strong&gt; lifecycle.&lt;/p&gt;

&lt;p&gt;Last but not least, you must remember that when passing a &lt;strong&gt;Parcelable&lt;/strong&gt; object as a &lt;strong&gt;Safe Args&lt;/strong&gt; argument, you must also add it to the proguard configuration, otherwise you will get a crash on production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;So is using Fragments the best solution? Probably not.&lt;/p&gt;

&lt;p&gt;In my opinion, it would be best if Google provided us with a ready, working and good API for navigation in Compose. Unfortunately, as I mentioned before, we can forget about it for now. At the moment, the solution that I presented is something that I use myself and I’m OK with it, at least for now.&lt;/p&gt;

&lt;p&gt;We should also remember that many libraries and tools do not yet have 100% support with Compose and sometimes the ability to write something in the old way, in a &lt;strong&gt;Fragment&lt;/strong&gt; or even in &lt;strong&gt;XML&lt;/strong&gt; is exactly what we need.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Thanks for reading!&lt;/strong&gt;&lt;br&gt;
That’s it for this article. I hope you like it and should you have any questions, do not hesitate to comment or reach out to me :)&lt;/p&gt;

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