跳转到正文
YGJoon
返回

Android Kotlin Hilt 依赖注入实战

编辑文章

Hilt 结构

项目配置

plugins {
    id("com.android.application")
    kotlin("android")
    kotlin("kapt")
    id("com.google.dagger.hilt.android")
}

dependencies {
    implementation("com.google.dagger:hilt-android:2.51.1")
    kapt("com.google.dagger:hilt-android-compiler:2.51.1")
    implementation("androidx.hilt:hilt-navigation-compose:1.2.0")
}

Application:

@HiltAndroidApp
class App : Application()

模块定义

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    @Provides
    fun provideOkHttpClient(): OkHttpClient = OkHttpClient.Builder().build()

    @Provides
    fun provideRetrofit(client: OkHttpClient): Retrofit = Retrofit.Builder()
        .baseUrl("https://api.example.com")
        .client(client)
        .addConverterFactory(MoshiConverterFactory.create())
        .build()
}

ViewModel 注入:

@HiltViewModel
class HomeViewModel @Inject constructor(
    private val repository: HomeRepository
) : ViewModel() {
    val uiState = MutableStateFlow<HomeUiState>(HomeUiState.Loading)
}

@AndroidEntryPoint
class HomeActivity : ComponentActivity() {
    private val viewModel: HomeViewModel by viewModels()
}

自定义作用域

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class FeatureScope

@Module
@InstallIn(ActivityRetainedComponent::class)
object FeatureModule {
    @Provides
    @FeatureScope
    fun provideFeatureRepository(api: FeatureApi): FeatureRepository {
        return FeatureRepository(api)
    }
}

与 Compose 集成

@Composable
fun HomeRoute(viewModel: HomeViewModel = hiltViewModel()) {
    val state by viewModel.uiState.collectAsState()
    HomeScreen(state)
}

动态特性模块

@EntryPoint
@InstallIn(SingletonComponent::class)
interface FeatureEntryPoint {
    fun homeNavigator(): HomeNavigator
}

fun Context.loadFeature(): HomeNavigator {
    val entryPoint = EntryPointAccessors.fromApplication(this, FeatureEntryPoint::class.java)
    return entryPoint.homeNavigator()
}

测试策略

@HiltAndroidTest
@UninstallModules(NetworkModule::class)
class HomeViewModelTest {
    @get:Rule
    val hiltRule = HiltAndroidRule(this)

    @BindValue
    lateinit var repository: HomeRepository

    @Before
    fun setup() {
        repository = FakeHomeRepository()
        hiltRule.inject()
    }
}

常见问题

问题原因解决方案
找不到入口Application 未标记 @HiltAndroidApp检查清单与注解
多模块依赖冲突不同模块重复定义 @InstallIn使用 @EntryPoint 接入跨模块依赖
热启动慢初始化对象过多分离懒加载,使用 @Provides @Singleton 缓存

总结

  1. Hilt 简化了 Dagger 配置,搭配 Kotlin 特性可实现清晰的依赖图。
  2. 注意作用域与模块划分,确保依赖生命周期与业务一致。
  3. 构建完整的测试替换策略,有助于验证依赖注入是否正确配置。

编辑文章
分享这篇文章:

上一篇
Android Kotlin Jetpack Compose 实战指南
下一篇
Android Kotlin Gradle Kotlin DSL 与构建优化