Dagger Hilt : My Beginner’s Experience

Jonas Boateng
4 min readFeb 12, 2021
Photo by Jimmy Chang on Unsplash

I might have been late to the party but as a self-taught developer, I only heard about Dagger for DI in 2016 during an interview. As you may have guessed, I didn’t get the job and so my acquaintance with Dagger was just a brief one. Fast forward to 2018 and my real introduction begun — I got a job and guess who was all over the codebase!!!.

Saying Dagger has a steep learning curve is an understatement. I mean where do I begin? I have to create components (and their subcomponents if needed), modules and then there is @Binds and @Provides and scoping with @Singleton and other lifecycle custom scopes that I will need to create for activities and fragments and services. And creating custom scopes with @Scope wasn’t intuitive for me either. It took me a while to develop the mental model that modules are where I bind/provide my dependencies. Then the modules used in components. Components will then list my Android system components such as activity and fragment. To make matters worse, there was no senior developer I could consult whenever I hit a bump so I was at the mercy of SO and other medium articles.

With the steep learning curve and my experience level, I was never sure if I was doing the right thing or following the (almost non-existence) best practices with my Dagger implementation. To say it bluntly, my confidence in my DI implementation using Dagger was low. This makes me always on the lookout for a better way of using it. I tried using Koin as well but that was for a practice app so I didn’t even bother to use it in the production app.

When Hilt was released with the hype around it, I decided this might be a good place to start building confidence in my DI implementation. Following a Codelab by Google, I dug my foot into it. Below is my experience with Hilt so far.

Easy Setup?

There wasn’t much difference between my Gradle setup using Dagger vs Hilt. However beginning with my custom Application class, there was no need to add any manual injection code using Hilt. All I needed to do was annotate the class with @HiltAndroidApp and Hilt was ready to work. This simple annotation means I could remove about 20 lines of code from the class.

Remember I told you about my mental map of when to use Components and Modules in Dagger? Well with Hilt, using built in annotations and scopes, I didn’t have to create any components when I was creating my modules. All I needed to do was use @InstallIn(ApplicationComponent::class) for any modules I wanted to use for the lifetime of the app. Hilt comes with couple of components built-in depending on the lifecycle of the modules you are using. Also using @AndroidEntryPoint annotation for my fragments and activities, I am able to inject my dependencies into my activities and fragment. This made my Component classes entirely useless. Using the actual dependencies in these classes was same as in Dagger — use @Inject then inject the said dependency.

Hilt modules are almost same as Dagger modules with one exception — use @InstallIn annotation to decide the level of scope you want the module to cover. For example, you can use @InstallIn(FragmentComponent::class) for modules scoped to Fragments while activity would be @InstallIn(ActivityComponent::class). Other components are available (link).

Tips Bits

If you have a dependency you want to provide/bind at different levels of the app, you can Qualifiers with @Qualifier annotation. Once you provide the name and assigned to a particular bind/provide, you can use that name at the point of injection.

My code had couple of base/parent fragments which provided common methods to children fragments. Following Dagger example, I could inject during fragment’s onAttach for both parent and child fragment. I had a bit a problem getting same implementation to work with Hilt and according to this link, a bit of refactor could work. Following the example given didn’t work for me and what worked was just annotating only the implementing/child fragment with @AndroidEntryPoint — don’t annotate the base/parent with @AndroidEntryPoint. You can still use all injected dependencies in abstract/base/parent fragment in all implementing/children fragments.

Use @Binds if you intend to provide the dependency through an interface/abstract class without providing how the dependency is made and @Provides for the opposite.

Ending note

Although Hilt does’t provide as much flexibility as Dagger, I find it easier to use as it seems to understand Android better. Also I believe unless your use case is very specific, the components and scopes already built-in with Hilt can cover most apps and implementations. Overall, I think Hilt makes DI a lot easier and also makes it difficult to abuse it usage — you would need to really try hard to do that. Hilt kind of provide its own best practise without necessarily saying so due to the way it works. I am now ready to release my production app completely migrated from Dagger to Hilt.

Side note: For anyone who has made it this far, thank you for reading my article. This is my very first medium post, feel free to help me improve. I hope to be posting more later.

--

--