Hilt 依赖注入
问题
Hilt 是什么?它如何简化 Android 中的依赖注入?
答案
核心概念
Hilt 是基于 Dagger 的 Android 依赖注入库,通过注解自动生成 Dagger 组件和模块,大幅减少模板代码。
基本配置
build.gradle.kts
plugins {
id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.51")
ksp("com.google.dagger:hilt-compiler:2.51")
}
核心注解
// 1. @HiltAndroidApp —— Application 入口
@HiltAndroidApp
class MyApp : Application()
// 2. @AndroidEntryPoint —— 启用注入的 Android 组件
@AndroidEntryPoint
class UserActivity : AppCompatActivity() {
@Inject lateinit var analytics: Analytics // 字段注入
}
// 3. @Inject —— 构造器注入(推荐)
class UserRepository @Inject constructor(
private val api: UserApi,
private val db: UserDao
)
// 4. @Module + @InstallIn —— 提供无法构造器注入的依赖
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient =
OkHttpClient.Builder()
.addInterceptor(HttpLoggingInterceptor())
.build()
@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit =
Retrofit.Builder()
.baseUrl("https://api.example.com/")
.client(client)
.addConverterFactory(GsonConverterFactory.create())
.build()
@Provides
fun provideUserApi(retrofit: Retrofit): UserApi =
retrofit.create(UserApi::class.java)
}
// 5. @Binds —— 绑定接口和实现
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {
@Binds
abstract fun bindUserRepository(impl: UserRepositoryImpl): UserRepository
}
组件层次与作用域
ViewModel 注入
@HiltViewModel
class UserViewModel @Inject constructor(
private val repository: UserRepository,
private val savedStateHandle: SavedStateHandle
) : ViewModel()
// Activity/Fragment 中
@AndroidEntryPoint
class UserFragment : Fragment() {
private val viewModel: UserViewModel by viewModels()
}
常见面试问题
Q1: Hilt 相比 Dagger 简化了什么?
答案:
| Dagger | Hilt |
|---|---|
| 手动定义 Component | 预定义 Android 组件层次 |
| 手动管理 Component 生命周期 | 自动绑定到 Android 组件生命周期 |
手动注入(component.inject(this)) | @AndroidEntryPoint 自动注入 |
| 自定义 Scope | 预定义 Scope(@Singleton、@ViewModelScoped 等) |
Q2: @Provides 和 @Binds 的区别?
答案:
@Provides:提供具体实例,方法体中写创建逻辑。用于第三方库对象(Retrofit、OkHttp)@Binds:绑定接口和实现,不需要方法体(必须是 abstract)。编译后性能更优
Q3: 如何在测试中替换依赖?
答案:
使用 @TestInstallIn 替换生产环境的 Module:
@Module
@TestInstallIn(
components = [SingletonComponent::class],
replaces = [NetworkModule::class]
)
object FakeNetworkModule {
@Provides
fun provideUserApi(): UserApi = FakeUserApi()
}