Dependency Injection with Hilt
What is dependency injection?
“Dependency injection” (DI) sounds scary but means something simple: instead of a class creating the objects it needs, those objects are given to it. This makes classes easier to test (you can pass in fakes) and removes messy manual wiring.
Without DI, a ViewModel might do val repo = UserRepository(ApiService(), UserDao()) — and now it’s tied to exact implementations. With DI, the repository is simply handed in.
Hilt: DI made easy for Android
Hilt is Google’s DI library built on Dagger. You annotate things, and Hilt generates all the wiring.
// 1. mark your Application
@HiltAndroidApp
class MyApp : Application()
// 2. tell Hilt how to provide things
@Module
@InstallIn(SingletonComponent::class)
object AppModule {
@Provides @Singleton
fun provideApi(): ApiService =
Retrofit.Builder().baseUrl("https://api.example.com/")
.addConverterFactory(MoshiConverterFactory.create())
.build().create(ApiService::class.java)
}
Injecting into a ViewModel
@HiltViewModel
class UsersViewModel @Inject constructor(
private val repo: UserRepository
) : ViewModel() { /* ... */ }
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val viewModel: UsersViewModel by viewModels()
}
Hilt sees the constructor needs a UserRepository, which needs an ApiService, and builds the whole chain for you.
Common mistakes
- Forgetting
@HiltAndroidAppon the Application class. - Forgetting
@AndroidEntryPointon the Activity/Fragment. - Over-using
@Singleton— only share objects that are genuinely app-wide.
Summary: DI means “objects are given, not created”. Hilt automates the wiring with a few annotations, making your app cleaner and far easier to test.