Hilt 是 Google 基于 Dagger 开发的 Android 专属依赖注入框架,大幅简化了 Dagger 的配置复杂度。以下是核心要点:
一、基础配置
-
项目级
build.gradle:dependencies { classpath 'com.google.dagger:hilt-android-gradle-plugin:2.48.1' } -
模块级
build.gradle:plugins { id 'kotlin-kapt' id 'com.google.dagger.hilt.android' } dependencies { implementation 'com.google.dagger:hilt-android:2.48.1' kapt 'com.google.dagger:hilt-compiler:2.48.1' } -
初始化 Application:
@HiltAndroidApp class MyApp : Application() // 必须添加此注解
二、核心注解及功能
| 注解 | 作用场景 | 说明 |
|---|---|---|
@HiltAndroidApp | Application 类 | 触发 Hilt 代码生成,生成顶层依赖容器 SingletonComponent |
@AndroidEntryPoint | Android 组件(Activity/Fragment/Service/View) | 使该组件支持依赖注入,必须添加到支持组件的类上 |
@Inject | 构造函数/字段 | 标记需要注入的依赖(构造函数)或声明需要注入的字段(属性注入) |
@Module | 依赖提供模块类 | 定义提供依赖的模块 |
@InstallIn | Module 类 | 指定模块的作用域(如 SingletonComponent::class) |
@Provides | Module 内部方法 | 提供实例(适用于第三方库/无法修改构造的类) |
@Binds | Module 内部抽象方法 | 绑定接口到实现类(更高效,需在抽象类/接口中使用) |
@Singleton | @Provides/@Binds方法 | 声明单例依赖(作用域为 SingletonComponent) |
@HiltViewModel | ViewModel 类 | 提供 ViewModel 依赖注入 |
@Qualifier | 自定义注解 | 解决同一类型多实例冲突(需自定义注解) |
三、使用场景与代码示例
-
构造函数注入(推荐):
class UserRepository @Inject constructor( private val apiService: ApiService ) { ... } -
字段注入(Android 组件):
@AndroidEntryPoint class MainActivity : AppCompatActivity() { @Inject lateinit var userRepo: UserRepository } -
提供接口实现(
@Binds):@Module @InstallIn(SingletonComponent::class) interface AuthModule { @Binds fun bindAuthService(impl: AuthServiceImpl): AuthService } -
提供第三方库实例(
@Provides):@Module @InstallIn(SingletonComponent::class) object NetworkModule { @Singleton @Provides fun provideRetrofit(): Retrofit = Retrofit.Builder().baseUrl("...").build() } -
ViewModel 注入:
@HiltViewModel class ProfileViewModel @Inject constructor( private val userRepo: UserRepository ) : ViewModel() { ... } // Activity/Fragment 中使用 private val viewModel: ProfileViewModel by viewModels()
四、作用域与组件生命周期
Hilt 通过组件层级管理作用域,每个组件对应特定生命周期:
| 组件 | 作用域注解 | 生命周期 |
|---|---|---|
SingletonComponent | @Singleton | Application 生命周期 |
ActivityRetainedComponent | @ActivityRetainedScoped | 配置变更后仍存活(ViewModel 层级) |
ActivityComponent | @ActivityScoped | Activity 生命周期 |
FragmentComponent | @FragmentScoped | Fragment 生命周期 |
ViewComponent | @ViewScoped | View 生命周期 |
ViewModelComponent | @ViewModelScoped | ViewModel 生命周期 |
规则:
- 依赖的作用域必须 ≤ 组件的生命周期(例:
@ActivityScoped依赖不能用在@Singleton模块中) - 子组件可访问父组件的依赖,反之不行
五、复杂场景解决方案
-
同一类型多实例(使用
@Qualifier):// 定义限定符 @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class AuthInterceptorClient @Qualifier @Retention(AnnotationRetention.RUNTIME) annotation class LoggingInterceptorClient // 提供不同实例 @Module @InstallIn(SingletonComponent::class) object NetworkModule { @AuthInterceptorClient @Provides fun provideAuthClient(): OkHttpClient { ... } @LoggingInterceptorClient @Provides fun provideLoggingClient(): OkHttpClient { ... } } // 使用处指定 class UserRepo @Inject constructor( @AuthInterceptorClient private val client: OkHttpClient ) -
动态参数依赖(使用
@AssistedInject):// 添加依赖:implementation "com.squareup.inject:assisted-inject:0.8.1" class ImageLoader @AssistedInject constructor( private val networkService: NetworkService, @Assisted private val url: String // 动态参数 ) { @AssistedFactory interface Factory { fun create(url: String): ImageLoader } } // 使用 @AndroidEntryPoint class MyActivity : AppCompatActivity() { @Inject lateinit var imageLoaderFactory: ImageLoader.Factory fun loadImage() { val loader = imageLoaderFactory.create("https://example.com/img.png") } } -
非标准类获取依赖(使用
EntryPoint):@EntryPoint @InstallIn(SingletonComponent::class) interface MyEntryPoint { fun getDependency(): MyDependency } // 在非注入类中使用 val entryPoint = EntryPointAccessors.fromApplication(context, MyEntryPoint::class.java) val dependency = entryPoint.getDependency()
六、关键注解对比表
| 注解组合 | 适用场景 | 主要区别 |
|---|---|---|
@Provides vs @Binds | 提供依赖实现 | @Binds 用于抽象方法(效率更高) |
@Singleton vs @ActivityScoped | 作用域控制 | 生命周期范围不同 |
@Inject vs @Provides | 依赖提供方式 | @Inject 优先用于构造函数 |
@Qualifier vs @Named | 解决多实例冲突 | @Qualifier 是自定义注解的标准方式 |