Dependency Injection with Hilt in Android Applications

Dependency Setup

Add the following dependencies to your module-level build.gradle file:

dependencies {
    implementation("com.google.dagger:hilt-android:2.44")
    annotationProcessor("com.google.dagger:hilt-android-compiler:2.44")
}

Apply the Hilt plugin in the same file:

plugins {
    id("com.android.application")
    id("dagger.hilt.android.plugin")
}

In the project-level build.gradle file, include the Hilt Gradle plugin in the buildscript dependencies:

buildscript {
    dependencies {
        classpath("com.google.dagger:hilt-android-gradle-plugin:2.44")
    }
}

Application Class Configuration

Create a custom Application class annotated with @HiltAndroidApp. This annotation triggers Hilt's code generation and creates the necessary dependency injection infrastructure:

package com.example.di

import android.app.Application
import dagger.hilt.android.HiltAndroidApp

@HiltAndroidApp
class DemoApplication : Application()

Register this application class in your AndroidManifest.xml file under the <application> tag.

Basic Dependency Injection

To make a class available for injection, annotate its constructor with @Inject. This tells Hilt how to create instances of this class:

package com.example.di

import javax.inject.Inject

class UserRepository @Inject constructor() {
    fun getUserData(): String = "User data loaded successfully"
}

Inject dependencies into Android components using the @AndroidEntryPoint annotation and @Inject fields:

package com.example.di

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log

import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var userRepository: UserRepository

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        
        Log.d("DI", userRepository.getUserData())
    }
}

Hilt Modules

When you need to provide objects that cannot be cnostructor-injected (such as interfaces or third-party libraries), create a Hilt module using the @Module annotation:

package com.example.di

import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton

@Module
@InstallIn(SingletonComponent::class)
object AppModule {
    
    @Provides
    @Singleton
    fun provideUserRepository(): UserRepository {
        return UserRepository()
    }
}

The @InstallIn annotation specifies which Hilt component the module should be installed into. The SingletonComponent is the highest-level component, meaning the provided dependency will be created once and shared across the entire application lifecycle.

Testing singleton behavior confirms proper module configuration:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject
    lateinit var repository1: UserRepository

    @Inject
    lateinit var repository2: UserRepository

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        Log.d("DI", repository1.toString())
        Log.d("DI", "Same instance: ${repository1 === repository2}")
    }
}

Default Hilt Components

Hilt provides several predefined components that correspond to different Android lifecycle scopes. The component hierarchy allows for proper scoping of dependencies:

Component Scope
SingletonComponent Application
ActivityRetainedComponent Activity or Fragment retained state
ActivityComponent Activity
FragmentComponent Fragment

Context Injection with Qualifiers

Hilt allows injecting different types of Context using qualifiers. By default, @Inject uses the Application component:

class DataManager @Inject constructor(
    private val repository: UserRepository,
    private val appContext: Context,
    private val application: Application
) {
    fun getAppContextType(): String = appContext.javaClass.simpleName
    fun getApplicationType(): String = application.javaClass.simpleName
}

To inject Activity-specific context, use the @ActivityContext qualifier:

class DataManager @Inject constructor(
    private val repository: UserRepository,
    @ActivityContext private val activityContext: Context
) {
    fun getContextType(): String = activityContext.javaClass.simpleName
}

ViewModel Support with Hilt

Hilt provides first-class support for ViewModels. Add the following dependencies to enable ViewModel injection:

dependencies {
    implementation("com.google.dagger:hilt-android:2.44")
    annotationProcessor("com.google.dagger:hilt-android-compiler:2.44")
    
    implementation("androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha03")
    annotationProcessor("androidx.hilt:hilt-compiler:1.0.0-alpha03")
}

Create a ViewModel with constructor injection using @ViewModelInject:

package com.example.di

import androidx.hilt.lifecycle.ViewModelInject
import androidx.lifecycle.ViewModel

class UserViewModel @ViewModelInject constructor(
    private val repository: UserRepository
) : ViewModel() {
    
    val userData: String = repository.getUserData()
}

Observe the ViewModel in your Activity or Fragment:

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
    
    private val viewModel: UserViewModel by viewModels()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        
        Log.d("DI", viewModel.userData)
    }
}

Hilt streamlines dependency injection in Android by eliminating boilerplate code and providing a standardized approach to managing dependencies across different application components.

Tags: Android Hilt Dependency Injection Dagger kotlin

Posted on Tue, 14 Jul 2026 16:19:28 +0000 by surfer