跪拜 Guibai
← All articles
Android · Android Jetpack

Hilt Dependency Injection on Android: Setup, Scopes, and Multi-Binding for View and Compose

By Lesile ·
Read original on juejin.cn ↗ Google Translate ↗ Alt translation

Hilt's version sensitivity remains a time sink that AI assistants often get wrong, making a verified version tuple the fastest path to a working project. Understanding that `@Binds` and `@Provides` cannot coexist in one module prevents a cryptic KSP compilation error that otherwise stalls new adopters.

Summary

Getting a minimal Hilt project to compile still trips up developers who lean on AI instead of the official docs. The root cause is almost always a version mismatch between Kotlin, KSP, and Hilt. A working combination is Kotlin 2.0.21, KSP 2.0.21-1.0.28, and Hilt 2.57, with the `hilt-android-compiler` dependency routed through `ksp` rather than the deprecated `kapt`.

Once the build is stable, Hilt usage breaks down into three injection strategies. Constructor injection with `@Inject` works for classes you own. Interface injection requires an abstract `@Module` with `@Binds` to map an implementation to its contract. Third-party classes that can't have their constructors modified rely on `@Provides` inside a concrete `@Module`. A common compile-time trap is mixing `@Binds` and `@Provides` in the same module, which Hilt forbids.

Scope management follows a strict parent-child component hierarchy: `SingletonComponent` outlives the app process, `ActivityRetainedComponent` survives configuration changes, and `ActivityComponent` is destroyed on rotation. For injecting multiple instances of the same class, custom `@Qualifier` annotations let you tag both the provider functions and the injection sites, and those same qualifiers can be applied to function parameters when one injected object depends on a specific variant of another.

Takeaways
Kotlin 2.0.21, KSP 2.0.21-1.0.28, and Hilt 2.57 form a verified, compatible version set that avoids cryptic build errors.
The `hilt-android-compiler` dependency must be declared with `ksp`, not `kapt`, which is now deprecated.
Fields injected by Hilt cannot be private; the compiler rejects them outright.
A single `@Module` cannot contain both `@Binds` (abstract) and `@Provides` (non-static) methods; they must be split into separate modules.
`@Qualifier` annotations enable injecting multiple distinct instances of the same class, and can also be placed on `@Provides` function parameters to select a specific dependency variant.
`ActivityRetainedComponent` scoped objects survive screen rotations, while `ActivityComponent` scoped objects are destroyed and recreated.
Predefined qualifiers `@ApplicationContext` and `@ActivityContext` inject the correct Context without manual passing.
Conclusions

AI coding assistants frequently hallucinate Hilt version combinations, making the official documentation the only reliable source for a clean project setup.

The prohibition against mixing `@Binds` and `@Provides` in one module is a practical constraint that forces a clean separation between interface bindings and factory methods, which aligns with good modular design even if it initially feels like boilerplate.

Using `@Qualifier` on function parameters, not just on fields, is an under-documented pattern that lets a provider function declare exactly which variant of a dependency it needs, keeping the resolution logic inside the DI graph rather than in business code.

Concepts & terms
KSP (Kotlin Symbol Processing)
A Kotlin compiler plugin API that replaces `kapt` for annotation processing. It runs directly on Kotlin source code, offering faster builds than the Java-based `kapt`, and is now the required processor for Hilt.
ActivityRetainedComponent
A Hilt component scoped to an Activity's lifecycle but retained across configuration changes like screen rotation. It sits between `SingletonComponent` and `ActivityComponent` in the hierarchy and is analogous to a ViewModel's survival behavior.
@Qualifier
A Dagger annotation used to distinguish between multiple bindings of the same type. Developers define custom annotation classes annotated with `@Qualifier`, then apply them to `@Provides` methods and `@Inject` fields to specify which instance to use.
Source: juejin.cn ↗ Google Translate ↗ Backup ↗