Hilt 依赖注入
Hilt 是 Android 的依赖注入库,它构建在 Dagger 之上,提供了一种标准的方法将 Dagger 依赖注入合并到 Android 应用程序中。Hilt 通过为项目中的每个 Android 类提供容器并自动管理其生命周期,简化了 Dagger 的使用。
添加依赖
建议使用 KSP (Kotlin Symbol Processing) 来处理注解,因为它比 Kapt 更快。
项目根目录 build.gradle
plugins {
// ...
id("com.google.dagger.hilt.android") version "2.51.1" apply false
id("com.google.devtools.ksp") version "1.9.23-1.0.19" apply false
}app 模块 build.gradle
plugins {
id("com.android.application")
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")
}Hilt 应用类
所有使用 Hilt 的应用都必须包含一个带有 @HiltAndroidApp 注解的 Application 类。
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
class ExampleApplication : Application() { ... }这个注解会触发 Hilt 的代码生成,包括应用的基础类,该类充当应用级依赖项容器。
将依赖项注入 Android 类
在 Application 类中设置了 Hilt 后,就可以使用 @AndroidEntryPoint 注解其他 Android 类(如 Activity、Fragment)。
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
// 字段注入
@Inject lateinit var analytics: AnalyticsAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
}
}Hilt 支持以下 Android 类:
Application(使用@HiltAndroidApp)ViewModel(使用@HiltViewModel)ActivityFragmentViewServiceBroadcastReceiver
注意:如果您使用 @AndroidEntryPoint 为某个 Android 类添加注解,则还必须为依赖于该类的 Android 类添加注解。例如,如果您为某个 Fragment 添加注解,则还必须为使用该 Fragment 的任何 Activity 添加注解。
定义绑定 (Bindings)
为了让 Hilt 知道如何提供不同类型的实例,我们需要使用构造函数注入或模块。
构造函数注入 (@Inject)
这是最简单的方法。在类的构造函数上添加 @Inject。
class AnalyticsAdapter @Inject constructor(
private val service: AnalyticsService
) { ... }Hilt 模块 (@Module)
有时候无法使用构造函数注入(例如接口、或者第三方库的类)。这时需要使用 Hilt 模块。
模块是一个带有 @Module 注解的类,它还需要 @InstallIn 注解来指定模块安装到哪个组件中(决定了绑定的生命周期)。
使用 @Binds 注入接口
interface AnalyticsService {
fun analyticsMethods()
}
class AnalyticsServiceImpl @Inject constructor() : AnalyticsService {
override fun analyticsMethods() { ... }
}
@Module
@InstallIn(SingletonComponent::class)
abstract class AnalyticsModule {
@Binds
abstract fun bindAnalyticsService(
analyticsServiceImpl: AnalyticsServiceImpl
): AnalyticsService
}使用 @Provides 注入第三方类
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
fun provideLoginRetrofitService(): LoginRetrofitService {
return Retrofit.Builder()
.baseUrl("https://example.com")
.build()
.create(LoginRetrofitService::class.java)
}
}预定义绑定 (@ApplicationContext)
Hilt 默认提供了一些常用的绑定,最常用的是 Context。我们无需手动编写 Module 来提供它。
| 限定符 | 上下文类型 | 适用组件 |
|---|---|---|
@ApplicationContext | Application Context | 任何组件 (Singleton, Activity, etc.) |
@ActivityContext | Activity Context | ActivityComponent, FragmentComponent, ViewComponent |
class AnalyticsAdapter @Inject constructor(
@ApplicationContext private val context: Context
) { ... }组件和作用域 (Components & Scopes)
Hilt 提供了一组预定义的组件和对应的作用域注解。
| Hilt 组件 | 注入对象 | 作用域注解 |
|---|---|---|
SingletonComponent | Application | @Singleton |
ActivityRetainedComponent | ViewModel | @ActivityRetainedScoped |
ActivityComponent | Activity | @ActivityScoped |
FragmentComponent | Fragment | @FragmentScoped |
ViewComponent | View | @ViewScoped |
ServiceComponent | Service | @ServiceScoped |
如果将 @Singleton 用于某个绑定,Hilt 会确保在整个应用中只创建一个该类型的实例。
在 ViewModel 中使用 Hilt
使用 @HiltViewModel 注解 ViewModel,并在构造函数中使用 @Inject。
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
@HiltViewModel
class ExampleViewModel @Inject constructor(
private val repository: ExampleRepository,
private val savedStateHandle: SavedStateHandle // Hilt 自动支持注入 SavedStateHandle
) : ViewModel() {
// ...
}然后在 Activity 或 Fragment 中像往常一样获取 ViewModel:
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {
private val viewModel: ExampleViewModel by viewModels()
// ...
}限定符 (Qualifiers)
如果某个类型有多种实现(例如两个不同的 String 或两个不同的 Retrofit 实例),可以使用限定符。
定义注解:
kotlin@Qualifier @Retention(AnnotationRetention.BINARY) annotation class AuthInterceptorOkHttpClient @Qualifier @Retention(AnnotationRetention.BINARY) annotation class OtherInterceptorOkHttpClient在 Module 中使用:
kotlin@Module @InstallIn(SingletonComponent::class) object NetworkModule { @AuthInterceptorOkHttpClient @Provides fun provideAuthOkHttpClient( authInterceptor: AuthInterceptor ): OkHttpClient { return OkHttpClient.Builder() .addInterceptor(authInterceptor) .build() } }注入时使用:
kotlin@Inject constructor( @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient )