Dependency Injection with Hilt
Dependency injection means objects receive their dependencies instead of creating them. It makes code testable (swap a fake repository) and decoupled. You have already used the simplest form — constructor injection — throughout this part:
class ArticlesViewModel(private val repository: ArticleRepository) : ViewModel()
Hilt automates wiring this graph across the app.
Hilt uses annotation processing and an Application subclass. It is shown here as
idiomatic code; the CI example app uses manual constructor injection to stay
buildable without the extra toolchain.
Setup
// build.gradle.kts (root)
plugins { id("com.google.dagger.hilt.android") version "2.52" apply false }
// app/build.gradle.kts
plugins {
id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.52")
ksp("com.google.dagger:hilt-compiler:2.52")
implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
}
Application and entry points
@HiltAndroidApp
class MyApp : Application()
@AndroidEntryPoint
class MainActivity : ComponentActivity() { /* ... */ }
(Register MyApp via android:name=".MyApp" in the manifest.)
Providing dependencies
Bind an interface to an implementation, or @Provides a built object:
@Module
@InstallIn(SingletonComponent::class)
abstract class DataModule {
@Binds
abstract fun bindArticleRepository(impl: RemoteArticleRepository): ArticleRepository
}
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideApi(): ArticleApi = Retrofit.Builder()/* ... */.create(ArticleApi::class.java)
}
Injecting into a ViewModel
@HiltViewModel
class ArticlesViewModel @Inject constructor(
private val repository: ArticleRepository,
) : ViewModel() { /* ... */ }
Obtain it in Compose with hiltViewModel():
@Composable
fun ArticlesRoute(viewModel: ArticlesViewModel = hiltViewModel()) { /* ... */ }
Why bother?
Hilt removes manual factory boilerplate and gives you scoped, lifecycle-aware singletons. For tests, you can replace modules with fakes — or skip Hilt entirely and construct the ViewModel with a fake repository, as the example’s tests do.
Exercises
-
Convert a manually-constructed repository to a Hilt
@Bindsmodule (on paper or in a scratch project). -
Explain why depending on the
ArticleRepositoryinterface (not the implementation) makes the ViewModel easy to test.
Previous: Networking · Next: Background Work with WorkManager