Dagger.Hilt TLDR (updated for 2.31.2-alpha)

Lukas Vyletel
4 min readSep 5, 2020

--

A very short tutorial on how to use Dagger.Hilt if you don’t have time to read through the docs.

TLDR 2 minutes

Add gradle dependencies:

// project's build.gradle
dependencies {
// your other dependencies
// Dagger Hilt
classpath "com.google.dagger:hilt-android-gradle-plugin:2.31.2-alpha"
}
// app/build.gradle
dependencies {
// other dependencies

// Dagger Hilt
kapt "com.google.dagger:hilt-android-compiler:2.31.2-alpha"
implementation "com.google.dagger:hilt-android:2.31.2-alpha"
}

Apply these two gradle plugins to your app/build.gradle

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

Create your own Application class, can be as simple as this:

@HiltAndroidApp
class MyApplication : Application()

Notice the @HiltAndroidApp annotation, which is necessary for the dependency injection to work.

Register your application class in your AndroidManifest.xml:

<application
android:name=".MyApplication"
// other attributes
>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

Annotate constructor of the dependency you want to inject using @Inject annotation:

class SomeDependency @Inject constructor() {
val value = "I come from injected dependency"
}

Finally, inject the dependency to your activity or fragment:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var someDependency: SomeDependency
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

textView.text = someDependency.value
}
}

Done! You can run your project, someDependency contains an instance of SomeDependency , that was injected for you by Dagger.Hilt. Notice the @AndroidEntryPoint annotation of the class, that you need to add to any Activity or Fragment you want to inject dependencies into.

I have a multi-module architecture and want to support dependency injection

Actually this is it. The dependency itself could come from any gradle module (provided you depend on the module in gradle).

TLDR 5 minutes

Ok, so you want to depend on an interface, not an actual implementation of it. What do you do?

Let’s change our SomeDependency class to implement some interface:

interface SomeInterface {
val value: String
}

class SomeDependency @Inject constructor() : SomeInterface {
override val value = "I come from injected dependency"
}

And change activity code so that it depends on the interface:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject lateinit var someInterface: SomeInterface
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

textView.text = someInterface.value
}
}

Ok, running this you’ll get:

[Dagger/MissingBinding] com.example.daggerhilttldr.SomeInterface cannot be provided without an @Provides-annotated method

You need to create a Dagger @Module, class that will tell Dagger, which implementation of SomeInterface to actually inject.

This is an example module:

@Module
@InstallIn(SingletonComponent::class)
interface AppModule {
@Binds fun bindsSomeInterface(impl: SomeDependency): SomeInterface
}

The module needs to be annotated by @Module annotation, that comes from Dagger 2. This annotation means, that the class or interface annotated by it provides clues for Dagger, how to construct certain dependencies. For example how to construct instances of an interface, should some class depend on that interface.

The module also needs to be annotated by @InstallIn(SingletonComponent::class) . This annotation tells, that dependencies defined here can be accessed by any class in the app. You could install the module into some other @Component and thereby control which classes of your app have access to which dependencies, but this topic is outside of the scope for this tutorial and most projects probably won’t need it anyway. You can learn more in the docs.

I want to share the same instance of SomeInterface across the whole app

Ok, easy, just add @Singleton annotation in the @Binds method signature, like this:

@Binds @Singleton fun bindsSomeInterface(impl: SomeDependency): SomeInterface

Bonus: I want to inject ViewModel into my Activity/Fragment

Provided you already have added all relevant gradle dependencies, you’ll need to add some new Android Jetpack dependencies:

implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha07'

Now if you want to inject dependencies into your ViewModel, use the standard@Inject annotated constructor, like you would in other classes. On top of that annotate the whole class with @HiltViewModel :

@HiltViewModel
class
MainViewModel @Inject constructor(
private val someInterface: SomeInterface
) : ViewModel() {
val state = someInterface.value
}

Adding the ViewModel to activity/fragment is trivial:

private val viewModel: MainViewModel by viewModels()

The whole activity class:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: MainViewModel by viewModels()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

textView.text = viewModel.state
}
}

If you’ve tried to use dependency injection with Dagger 2 on Jetpack ViewModel , you know how painful it was. Now it’s easy, using just this one annotation @ViewModel inject. The library takes care of the rest for you automatically.

But Dagger.Hilt is still in alpha!

It is. But it already works well. Being in alpha mostly means, that some APIs could change, but the simple use cases presented here are in my humble opinion unlikely to change. Personally, I’d recommend using Dagger.Hilt over Dagger.Android at this point, but should you for whatever reason decide to go with the bit older Dagger.Android and don’t know where to start, I’ve got you covered.

I’ve created a demo project and published it on Github, if you’d like to get hands on working implementation. You can view changes by commits, they roughly represent steps described in this article to integrate Dagger.Hilt to your app: https://github.com/lukas1/Dagger.Hilt.TLDR

--

--