Benefits and downsides of Dagger and Koin
Ahh, right here we go once more. The everlasting wrestle between Dagger/Hilt and Koin. I count on a number of arguments once more within the feedback about which one is healthier, however don’t fear guys, this text was created solely to indicate you the primary variations between them. Each of them are nice, so it’s a must to select which one you need to use by yourself, however I hope I’ll make this alternative a little bit simpler for you by displaying you their benefits and downsides for Jetpack Compose apps!
For the needs of this text I’m gonna assume that you simply already know what Dependency Injection is and what are the primary variations between Dagger/Hilt and Koin, for instance:
- Code technology vs. no code technology
- Impression on construct time vs. impression on runtime and injection time
- And clearly Hilt is really useful and maintained by Google, whereas Koin will not be. In fact, Google doesn’t say that Koin is dangerous and to make use of what you suppose matches higher to your undertaking.
Right here’s Manuel Vivo’s opinion about Koin, for instance:
Google recommends Hilt for Android apps however that’s only a suggestion! Use what you suppose it’s good for you.
If none of this sounds acquainted then you need to in all probability cease studying for a second and first determine what Dependency Injection, Dagger, Hilt and Koin are earlier than persevering with.
Okay, so now let’s evaluate Dagger/Hilt and Koin.
To greatest current the Execs and Cons of every of those instruments, I’ll take into account two instances the place you should use Jetpack Compose to write down Android Apps:
- The primary case — when your app is written in pure Jetpack Compose, that’s, with out utilizing Fragments, so that you’re in all probability utilizing navigation-compose library.
- And the second case — if you use Fragments and ComposeView (Interoperability), which for my part is your best option (at the least for now), largely due to the dangerous Navigation-Compose API and lack of sort security. That is fairly an enormous and controversial subject, however hey, that is what I like probably the most. Be sure you examine my article about this.
So what are a number of the good issues about Hilt?
Jetpack and Assist
To start with, Hilt is part of Jetpack and at present, Google recommends that you simply use it in your Android Apps. In fact, that’s not an enormous deal, however I have to say it’s very nice that Google created it, as a few of it’s possible you’ll know, utilizing Dagger was not all the time as good and satisfying as we want it to be — particularly for programmers who had been simply beginning to be taught Dependency Injection in Android.
Simpler to implement than Dagger
Second factor, like I’ve simply talked about, for those who had been utilizing Dagger earlier than and also you favored it, you’re gonna LOVE utilizing Hilt!
Compile-time errors
Dagger and Hilt are compile-time dependency injection frameworks. It signifies that if we unintentionally overlook to supply some dependency or we mess one thing up the construct is gonna fail and our app received’t run in any respect.
Koin will behave in a different way on this scenario. As you already know Koin doesn’t generate any code, so if we mess one thing up with DI the undertaking will construct anyway, however it would crash at begin or in a while some particular display screen.
The developer must examine whether or not the dependencies on this particular a part of the app are working effectively and the app doesn’t crash. Dagger/Hilt is far safer to make use of in that case.
Testing
The subsequent massive factor is Testing. For positive, writing Unit, UI, E2E, and so forth. assessments was already potential with Dagger, BUT what we get from Hilt now’s a lot, rather more! Overlook about difficult assessments with Dagger. Now you’ve got HiltAndroidRule
to handle the element’s state and to inject completely different dependencies to assessments simpler.
@HiltAndroidTest
class SettingsActivityTest @get:Rule
var hiltRule = HiltAndroidRule(this)
// UI assessments right here.
You may simply change and mock dependencies and even the entire modules on the fly. Additionally, you’ll be able to launch your Fragments (for those who’re utilizing them) in a particular take a look at container launchFragmentInHiltContainer
.
Should you’re not utilizing Fragments otherwise you need to take a look at solely the Composable, you’ll be able to simply do this with ComposeTestRule
, the place you’ll be able to go your ViewModel and different dependencies on to the Composable Operate (example on my Github). It is usually potential to routinely mock each ViewModel in your UI assessments, so the take a look at setup is just a few strains of code.
Course of dying
Securing your app towards course of dying can be quite a bit simpler with Hilt. You may merely inject SavedStateHandle
to the ViewModel
(which is only a fancy StateHandle map) to retailer and restore knowledge that must be saved in case of course of dying.
Is Hilt flawless? Let’s discover out.
Slower construct time
As most of you in all probability know Hilt generates some information throughout construct time, which signifies that the larger the app and the extra modules, elements and dependencies you’ve got, the longer your construct time is gonna get slower.
Typically it’s a must to write Dagger code
Whereas utilizing Hilt is far simpler than it was with Dagger, typically you’ll nonetheless want to make use of Dagger code in your app. If you wish to create separate android modules per function in your app then you definately’ll have to write down a few of your code in an old style approach with Dagger.
First, it’s a must to create a customized EntryPoint
module, mix it contained in the element’s builder after which programmatically inject it into the Exercise or Fragment that hosts the function. You may learn extra about it here.
You may’t inject something apart from ViewModel into Composables (at the least for now)
One of many main flaws for me is the truth that for those who’re writing a Compose solely app with out Fragments you’ll be able to’t inject dependencies into the Composables, apart from ViewModels.
Most likely a number of you might be questioning now, why would you even want one thing like that in any respect?
Effectively, initially that is actually a lack of performance, as a result of earlier than Compose we had been capable of inject dependencies into Fragments, Actions, and so forth. and now as Fragments had been “changed” by Composables you’d count on that this function must be nonetheless there, proper?
So are you able to give me some examples when it will be helpful?
Positive. Listed below are just a few examples:
- To delegate UI logic/work to different courses from Composables, so your code is extra reusable and concise.
- To render UI in a different way, primarily based on knowledge you get from particular dependencies like AppConfig or one thing else that doesn’t actually make sense to place within the ViewModel’s logic (as a result of there’s no logic). Instance: I need to show extra textual content within the Composable if I’m at present in DEBUG mode. I’ve the
isDebug: Boolean
worth inAppConfig
singleton. - One other instance: Let’s say you might want to have a number of Coil ImageLoaders and also you need to use them in a few of your Composables. You may’t inject them instantly into the Composable, so that you’d in all probability need to go them from the Exercise to the
NavGraph
after which both go it by way of Composable params or useCompositionLocalProvider
.
Can this drawback be solved simply? Sure.
As I advised you earlier than, I desire utilizing Compose with Fragments and that is one more reason why I nonetheless use them. You may simply inject dependencies inside Fragments after which go them alongside to Composables.
And what if I need to go the dependency actually deep into the Composable tree?
Effectively, first suppose twice if you really want to go it. If the reply continues to be sure then you’ll be able to both go the variable by way of every Composable down the tree or you’ll be able to consider using CompositionLocalProvider
. This requires you to write down extra code, however it’s nonetheless an choice.
Let’s begin with the Execs.
Approach simpler to make use of than Dagger and Hilt
To start with, Koin is unquestionably a lot easier to make use of and to be taught than Dagger or Hilt. It may be a sensible choice for novice programmers that need to be taught Dependency Injection.
You may inject dependencies into Composables
Not like Dagger or Hilt, Koin permits us to inject dependencies into Composables.
For instance:
@Composable
enjoyable SomeComposable(myService: MyService = get())
// ...
This solves the issue I’ve talked about earlier than and is very nice to have once we don’t use Fragments.
Extra informative error logs
Should you used Dagger or Hilt earlier than (particularly Dagger) you’ll have observed that they don’t give a lot information within the logs about errors that happen and also you typically need to guess and determine what is admittedly unsuitable.
For instance, in some instances Hilt would simply let you know:
[Hilt]
and that’s all.
In fact, over time these issues had been mounted and also you’ll see extra information now, however nonetheless, Koin wins this battle and has extra informative logs when errors occur.
No code technology
Koin received’t generate any code in any respect. Which means your construct occasions shall be faster.
And now the cons:
Rather more DI code, particularly get(), get(), get()… get()
As I discussed earlier than, Koin is far simpler to implement, however it comes with a worth — rather more code. Each singleton, manufacturing facility, viewModel, and so forth. you need to inject it’s a must to add to your modules first.
For instance:
val appModule = module
single DogRepository(get())manufacturing facility GetDogUseCase(get())
viewModel
DogDetailsViewModel(get())
So if in case you have a number of arguments in your dependencies your modules may find yourself like this:
val appModule = module
single
DogRepository(get(), get(), get(), get(), get())
manufacturing facility
viewModel
GetDogUseCase(
repo = get()
cacheRepo = get(),
service = get(),
somethingElse = get()
)
DogDetailsViewModel(
think about = get(),
a = get(),
lot = get(),
of = get(),
dependencies = get(),
right here = get()
)
And this is just one ViewModel and one Repo / UseCase. Think about how dangerous it would look in a much bigger app…
Points with SavedStateHandle when not utilizing Fragments
Presently, it’s not potential to inject SavedStateHandle
to your ViewModels for those who don’t use Fragments and inject your view fashions straight to the Composables. Should you strive to try this you’ll get an error. This must be mounted quickly, however it’s one thing it’s a must to take into account if you wish to protect display screen state in case of course of dying.
Impression on runtime efficiency
As I discussed earlier than Dagger/Hilt has a major impression on construct time as a result of code technology. Then again, Koin additionally impacts time, however not construct, however runtime. Koin has barely worse runtime efficiency, as a result of it resolves dependencies at runtime.

You will discover all the outcomes right here:
So which DI must you select to make use of? It’s a must to determine for your self. I have to admit I’m not an enormous fan of Dagger (sorry Dagger lovers), however I might nonetheless advocate studying it.
On the finish of the day, it’s not about which one is healthier however which one permits you to write clear code that’s straightforward to check and keep. I used all of them (Dagger, Hilt, Koin) in just a few initiatives earlier than and I feel all of them (particularly Hilt and Koin) match this criterion.
Try my different articles:
Additionally, for those who’re a Polish speaker, you’ll be able to hearken to my “Android Talks” Podcast episode about it: