Dagger/Hilt vs. Koin for Jetpack Compose Apps | by Patryk Kosieradzki | Mar, 2022

Photo by Mateusz Wacławek on Unsplash
  • Code generation vs. no code generation
  • Impact on build time vs. impact on runtime and injection time
  • 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.

Google recommends Hilt for Android apps but that’s just a recommendation! Use what you think it’s good for you.

  • 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.
  • 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. Be sure to check my article about this.

Jetpack and Support

Easier to implement than Dagger

Compile-time errors


class SettingsActivityTest {

var hiltRule = HiltAndroidRule(this)

// UI tests here.

process death

Slower build time

Sometimes you have to write Dagger code

You can’t inject anything other than ViewModel into Composables (at least for now)

  • To delegate UI logic/work to other classes from Composables, so your code is more reusable and concise.
  • 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.
  • 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.

Way easier to use than Dagger and Hilt

You can inject dependencies into Composables

fun SomeComposable(myService: MyService = get()) {
// ...

More informative error logs


No code generation

Much more DI code, especially get(), get(), get()… get()

val appModule = module {
single { DogRepository(get()) }

factory { GetDogUseCase(get()) }

viewModel {
val appModule = module {
single {
DogRepository(get(), get(), get(), get(), get())

factory {
repo = get()
cacheRepo = get(),
service = get(),
somethingElse = get()

viewModel {
imagine = get(),
a = get(),
lot = get(),
of = get(),
dependencies = get(),
here = get()

Issues with SavedStateHandle when not using Fragments

Impact on runtime performance

Source: https://github.com/Sloy/android-dependency-injection-performance

Leave a Comment