Hilt 依赖注入
基础用法
使用@HiltAndroidApp注解Application
kotlin
@HiltAndroidApp
class JetpackApp : Application()
使用@AndroidEntryPoint注解Activity
kotlin
@AndroidEntryPoint
class TestActivity: ComponentActivity()
定义被注入的类
kotlin
class TestBean @Inject constructor(val testValue: TestValue)
class TestValue @Inject constructor()
注入到Activity中
kotlin
@AndroidEntryPoint
class TestActivity: ComponentActivity() {
@Inject
lateinit var testBean: TestBean
}
Hilt模块
1.注入接口类型
定义接口和实现类
kotlin
interface ITestInterface
class TestInterface @Inject constructor(): ITestInterface
在Module中绑定实现类
kotlin
@Module
@InstallIn(ActivityComponent::class)
abstract class HiltModule {
@Binds
abstract fun bindITestInterface(
testInterface: TestInterface //实现接口的实现类
): ITestInterface //接口类型
}
在Activity中注入依赖
kotlin
//注入接口依赖
@Inject
lateinit var interfaceBean: ITestInterface
2.使用@Provides注入实例
kotlin
/**
* 构造方法不能修改的类
*/
class ProvideTestBean
在模块中提供ProvideTestBean
kotlin
@Module
@InstallIn(ActivityComponent::class)
class HiltModule1 {
@Provides
fun provideTestBean(): ProvideTestBean {
return ProvideTestBean()
}
}
3.为同一类型提供多个绑定
1.定义不同类型的注解
kotlin
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AutoTestBean
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherTestBean
2.在模块中使用定义的注解
kotlin
@Module
@InstallIn(ActivityComponent::class)
class HiltModule1 {
@Provides
@AutoTestBean
fun provideAutoTestBean(): TypeTestBean {
return TypeTestBean()
}
@Provides
@OtherTestBean
fun provideOtherTestBean(): TypeTestBean {
return TypeTestBean("其他")
}
}
3.在Activity注入不同的类型
kotlin
//同一类型多个绑定
@Inject
@AutoTestBean
lateinit var autoTestBean: TypeTestBean
//同一类型多个绑定
@Inject
@OtherTestBean
lateinit var otherTestBean: TypeTestBean
Hilt组件
在模块中使用@InstallIn将模块安装到指定组件中。如上面的例子中使用@InstallIn(ActivityComponent::class)将模块安装到Activity组件中
1.内置组件
2.组件生命周期
Hilt 会按照相应 Android 类的生命周期自动创建和销毁生成的组件类的实例。
3.组件的作用域
默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例。
Hilt 允许使用注解将绑定的作用域限定为特定组件,限定作用域内注入的依赖都是同一个实例
kotlin
/**
* 作用域为Activity的被依赖类
*
* @constructor Create empty Test bean activity scoped
*/
@ActivityScoped
class TestBeanActivityScoped @Inject constructor()
/**
* 作用域为全局的被依赖类
*
* @constructor Create empty Test bean singleton
*/
@Singleton
class TestBeanSingleton @Inject constructor()
/**
* 在模块中限定作用域
*/
@Provides
@Singleton
fun provideSingletonBean(): SingletonBean {
return SingletonBean(ProvideTestBean())
}
如果模块安装到子组件,则不允许限定父级的作用域,如@InstallIn(ActivityComponent::class)的模块不允许使用@Singleton,编译会直接报错
4.组件层次结构
将模块安装到组件后,其绑定就可以用作该组件中其他绑定的依赖项,也可以用作组件层次结构中该组件下的任何子组件中其他绑定的依赖项:
如安装到SingletonComponent的可以在整个应用中注入,如ViewModel、Activity、Fragment中注入,安装到ActivityComponent可以在Activity、Fragment中注入,但是安装在FragmentComponent则不可以在Activity中注入
ViewWithFragmentComponent 位于 FragmentComponent 下。FragmentComponent 和 ViewComponent 位于 ActivityComponent 下。ActivityComponent 位于 ActivityRetainedComponent 下。ViewModelComponent 位于 ActivityRetainedComponent 下。ActivityRetainedComponent 和 ServiceComponent 位于 SingletonComponent 下。
5.组件总结(个人理解)
- 可以将模块安装到不同组件中,不同组件对应着不同的注入对象
- 安装到组件中的模块生命周期和注入对象的生命周期关联,注入对象销毁了才会把依赖对象销毁
- 被依赖的对象默认没有限定作用域,可以使用注解限定作用域,限定作用域后会安装到对应的组件
- 子组件对应的注入对象内可以注入父组件中提供的依赖项,反过来不可以
6.注入ViewModel
无需自己写factory
kotlin
@HiltViewModel
class LoginViewModel @Inject constructor(val userRepository: UserRepository) : ViewModel()
//注入到Activity
@AndroidEntryPoint
class TestViewModelActivity :FragmentActivity(R.layout.activity_view_model){
private val mViewModel: TestActivityViewModel by viewModels()
}
//注入到Compose
@Composable
fun LoginScreen(
navController: NavHostController,
viewModel: LoginViewModel = hiltViewModel(),
) {
......
}