How to migrate your DI from Dagger-Android to Hilt?
If you are using dependency injection in your Android application, there is a 99% chance that Dagger is your mate. You might also know that this friendship can be really complicated and complex sometimes, especially in the beginning.
But not so long ago, Dagger had a “baby”, called Hilt, and I felt like I needed to celebrate this occasion by writing a blog post about our first official encounter.
What can Hilt do better than Dagger-Android?
But seriously though, I recently got a task in the company to migrate the DI in our internal framework from dagger-android to hilt. Fortunately, it was much easier than I thought it would be.
“Dependency injection (as a pattern not a library) benefits almost all code.
It promotes designing modular components which expose only the necessary APIs required to perform a specific action. When you are forced to break up pieces of your applications you have to consider how much implementation detail to expose, how the API behaves, and the visibility of classes and methods.
It promotes logical abstractions of components (think: interfaces and their implementations). You certainly don’t have to do this, but it ends up occurring organically anyway the more you DI things.
It facilitates testability by creating a single point of type consumption through which a class obtains something it needs. Need to swap out a Foo for a TestFoo? No problem. ’’ — Jake Wharton, stackoverflow comment
Dagger and Dagger-Android are the best-known libraries to use DI and solve your problems that Jake mentioned. Moreover, we just got Hilt, which comes from the same family, so you can play with Dagger and Hilt at the same time.
Hilt has awesome advantages to pimp out your DI things:
- It reduces boilerplate code by generating and providing default components to integrate Android framework classes, scope annotations, predefined bindings and predefined qualifiers.
- It makes your DI infrastructure more readable.
- It helps you to improve your tests.
Let’s start the migration
For the sake of simplicity, I’ve created a sample project:
$ git clone https://github.com/team-supercharge/dagger-hilt-example.git
There is the development branch that contains the state of the application before the migration. On the hilt-migration branch, you can find the final state after the migration.
Now check out the development branch and let’s start the exercise!
Update the root build.gradle file and add the Hilt dependency in the classpath:
Add the Hilt dependencies (hilt-compiler, hilt-android-compiler, hilt-android) to the app/build.gradle supplemented by the hilt-lifecycle-viewmodel dependency, because we have to use the @ViewModelInject annotation in the viewmodel migration process, also add the dagger.hilt.android.plugin that simplifies the usage of the library.
Migrate your ApplicationComponent
As I mentioned earlier, Hilt provides default components, so here we can use ApplicationComponent by Hilt. That is why we can remove our ApplicationComponent file.
Then update our HiltApplication class with the mandatory @HiltAndroidApp annotation and remove every other thing in the class:
And add @InstallIn annotation to your NotificationServiceModule. These annotations are required on all Dagger modules when using Hilt.
As you can see, we also have to add the @ApplicationContext predefined qualifier to providing the context for the NotificationManager.
Migrate your Activity and Fragment
You don’t need the ActivityModule and the FragmentModule anymore, just delete these two classes. This is because Hilt also generates an ActivityComponent and a FragmentComponent and they can replace our removed classes.
You must also remove the onAttach() method from the fragment and the AndroidInjection.inject(this) line from the activity.
Add @AndroidEntryPoint annotation to your MainMenuFragment and MainActivity classes and that’s all.
“Note: If you annotate an Android class with @AndroidEntryPoint, then you also must annotate Android classes that depend on it. For example, if you annotate a fragment, then you must also annotate any activities where you use that fragment.” — https://developer.android.com
Migrate your ViewModel
Open the MainMenuViewModel class. Change the @Inject to @ViewModelInject and Hilt will recognise and register this class to the ViewModelComponent.
Now, we can remove the ViewModelModule, ViewModelFactory classes and the qualifier package. After that, we must update the MainMenuFragment like that:
For the final step, also remove the dependencies of Dagger-Android:
Summary
It seems like the difference between the dependency graphs is really huge:
In addition, if you take a look at the codebase, the di package almost disappeared from the root project and a lot of boilerplate code was replaced by just some annotations. You don’t need to create those modules by hand and if you have a multi-module project with more than 10 modules, then it can spare a lot of time for you.
So, let’s welcome the new baby Hilt into the DI family.
At Supercharge, we are a next-generation innovation partner working with our clients to create transformative digital solutions. If you liked this article, check out some of Supercharge’s other articles on our blog, or follow us on LinkedIn, and Facebook. If you’re interested in open positions, follow this link.