Skip to Content
Android📚 Học lập trình AndroidDependency Injection với Hilt

Dependency Injection với Hilt

1. Giới thiệu

Hilt là DI library được Google xây dựng trên Dagger, đơn giản hóa DI trong Android.

2. Setup

// build.gradle.kts (project) plugins { id("com.google.dagger.hilt.android") version "2.51.1" apply false } // build.gradle.kts (app) plugins { id("com.google.dagger.hilt.android") id("com.google.devtools.ksp") } dependencies { implementation("com.google.dagger:hilt-android:2.51.1") ksp("com.google.dagger:hilt-compiler:2.51.1") // For Compose implementation("androidx.hilt:hilt-navigation-compose:1.2.0") }

3. Application Class

@HiltAndroidApp class MyApplication : Application()
<!-- AndroidManifest.xml --> <application android:name=".MyApplication" ...>

4. Activity

@AndroidEntryPoint class MainActivity : ComponentActivity() { @Inject lateinit var analytics: AnalyticsService override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // analytics is ready to use } }

5. ViewModel

@HiltViewModel class UserViewModel @Inject constructor( private val repository: UserRepository, private val savedStateHandle: SavedStateHandle ) : ViewModel() { // ... } // Usage in Compose @Composable fun UserScreen( viewModel: UserViewModel = hiltViewModel() ) { // ... }

6. Modules

Object Module

@Module @InstallIn(SingletonComponent::class) object NetworkModule { @Provides @Singleton fun provideOkHttpClient(): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(HttpLoggingInterceptor()) .build() } @Provides @Singleton fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit { return Retrofit.Builder() .baseUrl("https://api.example.com/") .client(okHttpClient) .addConverterFactory(GsonConverterFactory.create()) .build() } @Provides @Singleton fun provideApiService(retrofit: Retrofit): ApiService { return retrofit.create(ApiService::class.java) } }

Interface Bindings

@Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindUserRepository( impl: UserRepositoryImpl ): UserRepository }

7. Scopes

@Singleton // Application scope @ActivityScoped // Activity scope @ViewModelScoped // ViewModel scope @FragmentScoped // Fragment scope
@Module @InstallIn(SingletonComponent::class) object DatabaseModule { @Provides @Singleton // One instance for entire app fun provideDatabase(@ApplicationContext context: Context): AppDatabase { return Room.databaseBuilder( context, AppDatabase::class.java, "app_db" ).build() } }

8. Qualifiers

@Qualifier annotation class IoDispatcher @Qualifier annotation class MainDispatcher @Module @InstallIn(SingletonComponent::class) object DispatcherModule { @Provides @IoDispatcher fun provideIoDispatcher(): CoroutineDispatcher = Dispatchers.IO @Provides @MainDispatcher fun provideMainDispatcher(): CoroutineDispatcher = Dispatchers.Main } // Usage class UserRepository @Inject constructor( @IoDispatcher private val ioDispatcher: CoroutineDispatcher ) { suspend fun getUsers() = withContext(ioDispatcher) { // ... } }

9. Application Context

class AnalyticsService @Inject constructor( @ApplicationContext private val context: Context ) { // Use context safely }

10. Entry Points

Inject vào classes không được Hilt quản lý:

@EntryPoint @InstallIn(SingletonComponent::class) interface AnalyticsEntryPoint { fun analytics(): AnalyticsService } // Usage class MyContentProvider : ContentProvider() { private lateinit var analytics: AnalyticsService override fun onCreate(): Boolean { val entryPoint = EntryPointAccessors.fromApplication( context!!, AnalyticsEntryPoint::class.java ) analytics = entryPoint.analytics() return true } }

11. Testing

@HiltAndroidTest class UserViewModelTest { @get:Rule val hiltRule = HiltAndroidRule(this) @Inject lateinit var repository: UserRepository @Before fun setup() { hiltRule.inject() } @Test fun testViewModel() { // repository is injected } } // Replace module for testing @Module @TestInstallIn( components = [SingletonComponent::class], replaces = [RepositoryModule::class] ) object FakeRepositoryModule { @Provides @Singleton fun provideFakeRepository(): UserRepository = FakeUserRepository() }

12. Complete Example

// ApiService interface ApiService { @GET("users") suspend fun getUsers(): List<UserDto> } // Repository interface UserRepository { suspend fun getUsers(): Result<List<User>> } class UserRepositoryImpl @Inject constructor( private val api: ApiService, @IoDispatcher private val dispatcher: CoroutineDispatcher ) : UserRepository { override suspend fun getUsers() = withContext(dispatcher) { try { Result.success(api.getUsers().map { it.toDomain() }) } catch (e: Exception) { Result.failure(e) } } } // Module @Module @InstallIn(SingletonComponent::class) abstract class RepositoryModule { @Binds @Singleton abstract fun bindRepository(impl: UserRepositoryImpl): UserRepository } // ViewModel @HiltViewModel class UserViewModel @Inject constructor( private val repository: UserRepository ) : ViewModel() { // ... } // Composable @Composable fun UserScreen( viewModel: UserViewModel = hiltViewModel() ) { // ... }

📝 Tóm tắt

AnnotationMô tả
@HiltAndroidAppApplication class
@AndroidEntryPointActivity/Fragment
@HiltViewModelViewModel
@InjectConstructor injection
@ModuleProvide dependencies
@ProvidesProvide external classes
@BindsBind interface to impl
@SingletonApplication scope
Last updated on