Compose集成Hilt依赖注入
Hilt简化了Dagger在Android应用中的依赖注入,通过自动生成代码减少样板文件。它提供标准化组件和作用域,支持Activity、Fragment等Android组件的注入。使用KSP工具提升编译速度,通过Gradle插件简化配置。关键特性包括:应用类需使用@HiltAndroidApp注解,ViewModel通过@HiltViewModel注入,Compose中可用hiltViewMod
Hilt提供了一种将Dagger依赖注入集成到Android应用的标准方法。Hilt的工作原理是自动生成Dagger设置代码。这省去了使用Dagger的大部分样板代码,只保留了定义如何创建对象以及在哪里注入这些对象的部分。Hilt会生成Dagger组件以及自动注入Android类(例如Activity和Fragment)的代码。Hilt会根据传递类路径生成一组标准的Android Dagger组件。这需要使用Hilt注解标记Dagger模块,以告知Hilt它们应该被放入哪个组件中。在Android框架类中获取对象需要使用另一个Hilt注解,该注解会将Dagger注入代码生成到您将要扩展的基类中。对于Gradle用户,扩展此类是通过底层的字节码转换实现的。
Hilt的目标
- 简化Android应用的Dagger相关基础架构。
- 创建一套标准的组件和作用域,以简化设置、提高代码可读性和可理解性,并方便应用间的代码共享。
- 提供一种简便的方法来为各种构建类型(例如测试、调试或发布)配置不同的绑定。
为什么要使用Hilt
- 减少样板文字
- 解耦的构建依赖项
- 简化配置
- 改进测试
- 标准化组件
Gradle配置信息
在集成Hilt时,我们使用KSP工具来编译生成hilt代码。KSP是kotlin符号处理api,可用于开发轻量级编译器插件。KSP提供了一个简化的编译器插件API,它充分利用了Kotlin的强大功能,同时最大限度地降低了学习难度。与KAPT相比,使用KSP的注解处理器运行速度最高可提升2倍。
Hilt Gradle插件会运行字节码转换,以简化API的使用。该插件旨在提升IDE中的开发体验,因为生成的类可能会干扰基类方法的代码补全。文档中的示例均假设使用了该插件。要配置Hilt Gradle插件,首先需要在项目根build.gradle.kts文件中声明依赖项:
plugins {
id("com.google.dagger.hilt.android") apply false version "2.57.2"
id("com.google.devtools.ksp") apply false version "2.3.2"
}
在模块的build.gradle.kts文件中配置构建依赖
plugins {
id("com.google.dagger.hilt.android")
id("com.google.devtools.ksp")
}
dependencies {
implementation("com.google.dagger:hilt-android:2.57.2")
ksp("com.google.dagger:hilt-android-compiler:2.57.2")
}
对Application进行注入
所有应用在使用Hilt时必须包含一个带有@HiltAndroidApp注解的Application类,该注解会启动Hilt组件的代码生成,并为应用生成一个使用这些生成的组件的基类。示例如下
@HiltAndroidApp
class MyApplication : MyBaseApplication() {
@Inject lateinit var bar: Bar
override fun onCreate() {
super.onCreate() // Injection happens in super.onCreate()
// Use bar
}
}
对Android组件进行注入
在Application中启用成员注入后,可以使用@AndroidEntryPoint注解在其它Android类中启用成员注入,支持的组件如下
- Activity
- Fragment
- Service
- BroadcastReceiver
- View
注意:ViewModel是通过@HiltViewModel来支持
@AndroidEntryPoint
class MyActivity : ComponentActivity() {
@Inject lateinit var bar: Bar // Bindings in SingletonComponent or ActivityComponent
override fun onCreate() {
// Injection happens in super.onCreate().
super.onCreate()
// Do something with bar ...
}
}
注意:Hilt当前仅支持继承ComponentActivity的Activity和继承Androidx库的Fragment
使用Module提供注入对象
Hilt Module是标准的Dagger模块,它有一个额外的@InstallIn注解,用于确定将模块安装到哪个Hilt组件中。在Hilt 组件中安装模块时,需要使用注解为模块添加注解@InstallIn。使用Hilt时,所有Dagger模块都必须添加这些注解
注意:如果一个模块没有注解@InstallIn,则该模块将不会成为组件的一部分,并可能导致编译错误。
指定要将模块安装到哪个Hilt组件中,方法是将相应的组件类型传递给@InstallIn注解。例如要安装一个模块以便应用程序中的任何组件都可以使用它,请使用SingletonComponent:
@Module
@InstallIn(SingletonComponent::class) // Installs BarModule in the generate SingletonComponent.
internal object BarModule {
@Provides
fun provideBar(): Bar {
return Bar()
}
}
对ViewModel进行注入
Hilt ViewModel是由Hilt通过构造函数注入的Jetpack ViewModel。要启用Hilt对ViewModel的注入,请使用@HiltViewModel注解:
@HiltViewModel
class MainViewModel @Inject constructor(val bar: Bar) : ViewModel()
在Compose中注入ViewModel
配置lifecycle依赖
dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-compose:2.9.4")
}
通过调用viewModel()函数,从任何可组合项访问ViewModel。
@HiltViewModel
class MainViewModel @Inject constructor(val bar: Bar) : ViewModel()
// import androidx.lifecycle.viewmodel.compose.viewModel
@Composable
fun mainPage(viewModel: MainViewModel = viewModel()) {
// use viewModel here
}
viewModel()会返回一个现有的ViewModel,或创建一个新的ViewModel。默认情况下,返回的ViewModel的作用域限定为封装activity、fragment或导航目的地,并且只要该作用域处于有效状态,就会保留该ViewModel。 例如,如果在某个activity中使用了可组合项,则在该activity完成或进程终止之前,viewModel()会返回同一实例。viewModel()函数自动使用Hilt通过@HiltViewModel注解构造的ViewModel。
Hilt还适配了Navigation Compose库,集成如下:
dependencies {
implementation("androidx.hilt:hilt-navigation-compose:1.3.0")
}
使用Navigation Compose时,请始终使用hiltViewModel可组合函数获取带有@HiltViewModel注解的ViewModel的实例。该函数可与带有@AndroidEntryPoint注解的fragment或activity搭配使用。 例如,如果 mainPage是导航图中的目的地,请调用hiltViewModel()来获取作用域限定为该目的地的MainViewModel实例,如以下代码段所示:
// import androidx.hilt.navigation.compose.hiltViewModel
@Composable
fun myApp() {
val navController = rememberNavController()
val startRoute = "main"
NavHost(navController, startDestination = startRoute) {
composable("main") { backStackEntry ->
// Creates a ViewModel from the current BackStackEntry
// Available in the androidx.hilt:hilt-navigation-compose artifact
val viewModel = hiltViewModel<MainViewModel>()
mainPage(viewModel)
}
/* ... */
}
}
完整示例
@HiltAndroidApp
class MyApplication : MyBaseApplication()
@AndroidEntryPoint
class MyActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
myApp()
}
}
}
@Composable
fun myApp() {
val navController = rememberNavController()
val startRoute = "main"
NavHost(navController, startDestination = startRoute) {
composable("main") { backStackEntry ->
val viewModel = hiltViewModel<MainViewModel>()
mainPage(viewModel)
}
}
}
@Composable
fun mainPage(viewModel: MainViewModel = viewModel()) {
println(viewModel.getName())
}
@HiltViewModel
class MainViewModel @Inject constructor(private val bar: Bar) : ViewModel(){
fun getName(): String {
return bar.name
}
}
@Module
@InstallIn(SingletonComponent::class)
internal object BarModule {
@Provides
fun provideBar(): Bar {
return Bar("jinhongke")
}
}
data class Bar(private val name: String)
更多推荐


所有评论(0)