跳到主要内容

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 简化了什么?

答案

DaggerHilt
手动定义 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()
}

相关链接