跳到主要内容

跨模块依赖注入

问题

模块化项目中依赖注入如何跨模块工作?

答案

Hilt 跨模块注入

Hilt 天然支持跨模块依赖注入。每个模块可以独立定义 @Module,Hilt 在编译期自动聚合所有模块的 DI 配置:

app/                  ← @HiltAndroidApp
├── feature-home/ ← 定义自己的 @Module
├── feature-profile/ ← 定义自己的 @Module
└── core-network/ ← 提供网络相关的 @Module
core-network/NetworkModule.kt
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
@Singleton
fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder()
.connectTimeout(15, TimeUnit.SECONDS)
.build()

@Provides
@Singleton
fun provideRetrofit(client: OkHttpClient): Retrofit = Retrofit.Builder()
.baseUrl(BuildConfig.API_URL)
.client(client)
.addConverterFactory(MoshiConverterFactory.create())
.build()
}
feature-home/HomeModule.kt
@Module
@InstallIn(ViewModelComponent::class)
abstract class HomeModule {
@Binds
abstract fun bindHomeRepository(impl: HomeRepositoryImpl): HomeRepository
}
feature-home/HomeViewModel.kt
@HiltViewModel
class HomeViewModel @Inject constructor(
private val repository: HomeRepository, // 来自 HomeModule
private val retrofit: Retrofit // 来自 core-network
) : ViewModel()

接口与实现分离

core-service-api/IAuthService.kt
// 接口在公共 API 模块
interface IAuthService {
fun isLoggedIn(): Boolean
fun getToken(): String?
}
feature-auth/AuthServiceImpl.kt
@Singleton
class AuthServiceImpl @Inject constructor(
private val dataStore: DataStore<Preferences>
) : IAuthService {
override fun isLoggedIn(): Boolean = /* ... */
override fun getToken(): String? = /* ... */
}
feature-auth/AuthModule.kt
@Module
@InstallIn(SingletonComponent::class)
abstract class AuthModule {
@Binds
abstract fun bindAuthService(impl: AuthServiceImpl): IAuthService
}

Hilt vs Koin

维度HiltKoin
原理编译期代码生成运行时 ServiceLocator
类型安全编译期检查运行时报错
性能无运行时开销首次注入有反射开销
学习曲线较陡(Dagger 基础)简单(DSL)
多模块支持原生支持需要 loadKoinModules
推荐Google 官方推荐小型项目

常见面试问题

Q1: Hilt 的 Component 层级有哪些?

答案

SingletonComponent(Application 级)
├── ActivityRetainedComponent(ViewModel 级,配置变更不销毁)
│ ├── ViewModelComponent
│ └── ActivityComponent
│ ├── FragmentComponent
│ └── ViewComponent
│ └── ViewWithFragmentComponent
└── ServiceComponent

@InstallIn 决定 Module 注入到哪个层级。SingletonComponent 全局单例,ViewModelComponent 跟随 ViewModel 的生命周期。

Q2: feature 模块提供的 @Module 何时被 Hilt 发现?

答案

Hilt 使用 AGP 的 @InstallIn 注解 + 编译期代码生成。当 app 模块依赖 feature-home 时,Hilt 的注解处理器在 app 编译时会扫描所有传递依赖中的 @Module 注解类,自动将它们注册到对应的 Component 中。因此无需手动注册,只要模块在依赖图中即可。

相关链接