Migrating Dagger2 to Hilt in a Multi-module App using Clean Architecture

Damilola Omoyiwola
4 min readNov 22, 2020

--

Android Development community has rapidly grown with the improvement of libraries and components being released at short intervals. Consequently, we have experienced a lot of hassles with Dagger generally. Fortunately, Google recently released an improved version up to the hilt.

Following up on one of my recent articles on setting up dagger2 with clean architecture (CA) and multi-module, I’m glad to say that I will be sharing how I migrated dagger2 to hilt using the same project. Meanwhile, this is also useful when setting up hilt with clean architecture from scratch.

Hilt Overview

From the dagger.dev,

Hilt provides a standard way to incorporate Dagger dependency injection into an Android application.

The goals of Hilt are:

1. To simplify Dagger-related infrastructure for Android apps.

2. To create a standard set of components and scopes to ease setup, readability/understanding, and code sharing between apps.

3. To provide an easy way to provision different bindings to various build types (e.g. testing, debug, or release).

Let me assure you that it’s very easy to set up once you understand some key points and the respective annotations 🙂

Setting up Hilt in a few steps:

1. Add to the root project/build.gradle file

2. Add to the app/build.gradle file

Notice the gradle plugin in the app module, we specify it in the app/build.gradle file by adding the plugin to the top of the file, below the kotlin-kapt plugin in order to use the hilt gradle plugin.

Another good news is its support with ViewModel and in order to integrate this, you need to add the above dependencies.

3. Adding Hilt in the application class

Remember that in the current project, we have a module called core where we had dagger2 components, modules, and application class MainApplication.kt. You will notice in the core/hilt branch, there’s no core module again. This is the reason:

All apps using Hilt must contain an Application class annotated with @HiltAndroidApp. @HiltAndroidApp kicks off the code generation of the Hilt components and also generates a base class for your application that uses those generated components. Because the code generation needs access to all of your modules…

Let me explain the statement above with respect to the current project used.

Initially, the app module does not depend on the data, domain, presentation modules because it has no business with them except with the feature modules (competitions and competitiondetails modules).

But with Hilt, “All apps… must contain an Application class…”, the Hilt components and co are generated and they need access to ALL modules used in the project.

So, with this, we do not need the core module since hilt does not need a component class unlike dagger2. Therefore, the MainApplication.kt class is moved to the app module and annotated with @HiltAndroidApp. This annotation triggers the code generation.

See what we now have compared to the case of dagger2 😭 — All boilerplate codes GONE!

Note: We no longer need the dagger component classes at the feature module-level anymore.

Wait, we are not done yet 😃

4. Inject instances with @Provides

Since there are instances (such as interfaces) that are provided but cannot be injected via constructors, the Hilt Module provides a great way to achieve this by annotating with both @Module and @InstallIn.

@Module tells Hilt this is a module

@InstallIn tells Hilt in which containers the bindings are available by specifying a Hilt Component.

So, in the data module, we have DatabaseModule, DataModule, NetworkModule and are injected by Hilt Module as seen below:

In the DatabaseModule class, to access the database object, the field needs to be annotated with@ApplicationContext

5. Inject dependencies to classes (activities and fragments)

Hilt currently supports the following Android types: Application (by using @HiltAndroidApp), Activity, Fragment, View, Service and BroadcastReceiver.

Hilt only supports activities that extend FragmentActivity (like AppCompatActivity) and fragments that extend the Jetpack library Fragment, not the (now deprecated) Fragment from the Android platform.

This is how it is injected in a fragment:

We could see that there is no need for the code in the onAttach method any longer 👌.

6. Inject ViewModel objects with Hilt

Provide a ViewModel using the @ViewModelInject annotation in the ViewModel object's constructor.

That’s all? Yea, that’s all! 😆

You can check out its support for Jetpack libraries like WorkManager.

Here are the links for its official documentation on Android developers official guide and dagger.dev.

Conclusion

I think the Google team deserves some accolades 👏 👏 This feels so relieving😌 and I love it.

However, Hilt uses more of a monolithic approach which defeats the essence of modularisation. Although, it makes dependency injection easy to set up and reduces boilerplate codes.

It is still in its alpha stage, and we hope for more improvements.

Thanks for reading through!

If you have any comment, kindly drop it in the comment section below and if you ❤️ this article, please feel free to 👏 and share.

--

--