CHAPTER 28
Beginner
Dependency Injection (Hilt/Dagger)
Updated: May 16, 2026
30 min read
# CHAPTER 28
Dependency Injection (Hilt/Dagger)
1. Introduction
Throughout this curriculum, we have built complex, layered architectures. The Activity needs a ViewModel. The ViewModel needs a Repository. The Repository needs a Room DAO and a Retrofit API. Currently, we are manually instantiating these classes inside each other:val repository = UserRepository(Database.get(context), Retrofit.api). As an app scales to hundreds of screens, this manual "wiring" becomes a chaotic, unmaintainable nightmare of boilerplate code. Furthermore, it makes Unit Testing nearly impossible. The industry solution is Dependency Injection (DI). In this chapter, we will master Hilt, Google's official, Jetpack-recommended DI framework built on top of the powerful Dagger library. Hilt automatically constructs and provides dependencies exactly where they are needed.
2. Learning Objectives
By the end of this chapter, you will be able to:- Understand the core philosophy of "Inversion of Control" and Dependency Injection.
- Configure Hilt Gradle dependencies and plugins.
-
Initialize Hilt at the Application level via
@HiltAndroidApp.
-
Annotate UI controllers (Activities/Fragments) with
@AndroidEntryPoint.
-
Construct Hilt Modules and leverage
@Providesto instruct Hilt on object creation.
-
Seamlessly inject dependencies into ViewModels utilizing
@HiltViewModel.
3. What is Dependency Injection?
Without DI: "I am the ViewModel. I will build my own Repository utilizing thenew keyword." (High Coupling).
With DI: "I am the ViewModel. I need a Repository. Hey Hilt, please build one and hand it to me in my constructor." (Low Coupling, High Testability).
*Analogy:* You are a Chef. You shouldn't have to build your own oven before cooking. The restaurant (Hilt) should "inject" an oven into your kitchen.
4. Step 1: Hilt Gradle Setup
Hilt requires several plugins. Project-levelbuild.gradle.kts:
kotlin
App-level build.gradle.kts (Module :app):
kotlin
5. Step 2: The Application Class
Hilt needs a starting point to attach its massive, generated dependency graph.-
1.
Create a new Kotlin class named
MyApplicationextendingApplication.
-
2.
Annotate it with
@HiltAndroidApp.
-
3.
CRITICAL: Register this class in the
AndroidManifest.xmlinside the<application>tag usingandroid:name=".MyApplication".
kotlin
6. Step 3: Hilt Modules (@Provides)
Hilt is smart, but it doesn't know how to build a Retrofit instance or a Room Database unless you teach it. We do this inside a Module.
kotlin
7. Step 4: Injecting the Repository
Now that Hilt knows how to build aUserDao, we can tell Hilt to automatically build the Repository. We do this by adding @Inject constructor.
kotlin
8. Step 5: Injecting the ViewModel
Injecting ViewModels used to be very difficult. Jetpack Hilt makes it trivial via the@HiltViewModel annotation.
kotlin
9. Step 6: Injecting the Activity (@AndroidEntryPoint)
Finally, we must tell Hilt that our Activity wants to use injected dependencies. We annotate the Activity with @AndroidEntryPoint and use the viewModels() delegate.
kotlin
10. Common Mistakes
-
Forgetting the Manifest: You can write perfect Hilt code, but if you forget to add
android:name=".MyApplication"to theAndroidManifest.xml, Hilt will simply never start, and your app will crash instantly with injection errors.
-
Missing
@AndroidEntryPointon Fragments: If an Activity uses Hilt, but a Fragment inside it requests a ViewModel without having@AndroidEntryPointabove its class declaration, the app will crash.
11. Best Practices
-
Scoping Constraints: Do not arbitrarily add
@Singletonto every@Providesfunction. A Database should be a Singleton. But a simple temporary helper class should not be a Singleton, as it will persist in RAM forever and cause memory bloat. Let Hilt create new instances of lightweight objects.
12. Exercises
-
1.
Setup Hilt dependencies in Gradle and create the
MyApplicationclass. Don't forget the Manifest.
-
2.
Create an
AppModuleand write a@Providesfunction that returns aStringrepresenting a base API URL. Inject that string into a dummy Repository.
13. Coding Challenges
Challenge: Refactor a previous project. Take the app you built in Chapter 22 (Repository Pattern). Completely remove all manual instantiation of the Database, Retrofit, and Repository. Implement Hilt Modules and@Inject constructors to fully automate the dependency graph.
14. MCQ Quiz with Answers
Question 1
In the context of software architecture, what structural problem does Dependency Injection (DI) primarily solve?
Question 2
Within the Dagger Hilt framework, what is the explicit functional purpose of the @Provides annotation inside an @Module class?
15. Interview Questions
- Q: Explain the mechanics of "Inversion of Control". How does passing an Interface into a constructor via DI, rather than instantiating a concrete class directly, radically improve the testability of a system?
-
Q: Detail the lifecycle hierarchies utilized by Hilt Components. Why must a Room Database be installed within the
SingletonComponentrather than theActivityComponent?
- Q: Contrast traditional Dagger 2 with modern Dagger Hilt. What specific Android-centric boilerplate configuration steps did Hilt eliminate to become the Jetpack standard?
16. Summary
In Chapter 28, we conquered one of the most complex architectural paradigms in software engineering: Dependency Injection. By integrating Dagger Hilt, we eliminated massive amounts of rigid boilerplate code. We established an automated dependency graph utilizing@Module and @Provides configurations. We successfully utilized @HiltViewModel and @AndroidEntryPoint to automatically wire our entire MVVM architecture from the Database to the UI. Our application is now modular, highly decoupled, strictly testable, and engineered to enterprise-level scalable standards.