Hilt 是什么
Hilt 是 Android 的依赖项注入库,可减少在项目中执行手动依赖项注入的样板代码。执行手动依赖项注入要求您手动构造每个类及其依赖项,并借助容器重复使用和管理依赖项。
Hilt 通过为项目中的每个 Android 类提供容器并自动管理其生命周期,提供了一种在应用中使用 DI(依赖项注入)的标准方法。Hilt 在热门 DI 库 Dagger 的基础上构建而成,因而能够受益于 Dagger 的编译时正确性、运行时性能、可伸缩性和 Android Studio 支持。
依赖注入是什么
一个类里面有一个变量,这个变量就是这个类的依赖。然后通过外部注入对这个变量进行赋值,这种就叫做依赖注入
工厂、Builder模式、带参数的构造函数这些都属于依赖注入
引入Hilt
首先,将 hilt-android-gradle-plugin
插件添加到项目的根级 build.gradle
文件中:
buildscript {
...
dependencies {
...
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
}
}
然后,应用 Gradle 插件并在 app/build.gradle
文件中添加以下依赖项:
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'
android {
...
}
dependencies {
implementation "com.google.dagger:hilt-android:2.28-alpha"
kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}
Hilt 使用 Java 8 功能。如需在项目中启用 Java 8,请将以下代码添加到 app/build.gradle
文件中:
android {
...
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
Hilt基本使用
-
@HiltAndroidApp
@HiltAndroidApp 将会触发 Hilt 的代码生成,作为程序依赖项容器的基类
生成的 Hilt 依附于 Application 的生命周期,他是 App 的父组件,提供访问其他组件的依赖
所有使用 Hilt 的应用都必须包含一个带有@HiltAndroidApp
注释的Application
类。
@HiltAndroidApp
会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器。@HiltAndroidApp class ExampleApplication : Application() { ... }
在 Application 中配置好后,就可以使用 Hilt 提供的组件了;组件包含 Application,Activity,Fragment,View,Service 等。
-
@AndroidEntryPoint
创建一个依赖容器,该容器遵循 Android 的生命周期类,目前支持的类型是: Activity, Fragment, View, Service, BroadcastReceiver.@AndroidEntryPoint class MainActivity : AppCompatActivity()
-
@Inject
使用 @Inject 来告诉 Hilt 如何提供该类的实例,常用于构造方法,非私有字段,方法中。
Hilt 有关如何提供不同类型的实例信息也称之为绑定@Inject lateinit var orderManager: OrderManager class OrderManager @Inject constructor(private val addressInfo: AddressInfo) { fun payOrder() { println( "payOrder()执行了") } }
接口注入
@Module
module 是用来提供一些无法用构造@Inject 的依赖,如第三方库,接口,build 模式的构造等。
使用 @Module 注解的类,需要使用 @InstallIn 注解指定 module 的范围
增加了 @Module 注解的类,其实代表的就是一个模块,并通过指定的组件来告诉在那个容器中可以使用绑定安装。-
@InstallIn
使用 @Module 注入的类,需要使用 @InstallIn 注解指定 module 的范围。
例如使用 @InstallIn(ActivityComponent::class) 注解的 module 会绑定到 activity 的生命周期上。@Module @InstallIn(ApplicationComponent::class) abstract class PayModule
@Binds:必须注释一个抽象函数,抽象函数的返回值是实现的接口。通过添加具有接口实现类型的唯一参数来指定实现。
首先需要一个接口,和一个实现类
interface PayMethod {
fun startPay()
}
class WxPay @Inject constructor() : PayMethod {
override fun startPay() {
println("WxPay start.")
}
}
接着就需要新建一个 Module。用来实现接口的注入
@Module
@InstallIn(ApplicationComponent::class)
abstract class PayModule {
@Binds
abstract fun bindWxPay(wxPay: WxPay): PayMethod
}
注意:这个 Module 是抽象的。
使用如下:
@Inject
lateinit var wxPay: PayMethod
fun payOrder() {
wxPay.startPay()
println("print address ${addressInfo.province}")
wxPay.getPayResult()
}
给相同类型注入不同的实例
还是上面的 PayMethod 接口,有两个不同的实现,如下:
class WxPay @Inject constructor() : PayMethod {
override fun startPay() {
println("WxPay start.")
}
override fun getPayResult() {
println("WxPay getPayResult.")
}
}
class ZfbPay @Inject constructor() : PayMethod {
override fun startPay() {
println("ZfbPay start.")
}
override fun getPayResult() {
println("ZfbPay getPayResult.")
}
}
接着定义两个注解
@Qualifier
annotation class BindWxPay
@Qualifier
annotation class BindZfbPay
然后修改 Module ,在 module 中用来标记相应的依赖。
@Module
@InstallIn(ApplicationComponent::class)
abstract class PayModule {
@BindWxPay
@Binds
abstract fun bindWxPay(wxPay: WxPay): PayMethod
@BindZfbPay
@Binds
abstract fun bindZfbPay(zfbPay: ZfbPay): PayMethod
}
最后使用如下:
@BindWxPay
@Inject
lateinit var wxPay: PayMethod
@BindZfbPay
@Inject
lateinit var zfbPay: PayMethod
fun payOrder() {
wxPay.startPay()
zfbPay.startPay()
wxPay.getPayResult()
zfbPay.getPayResult()
}
Hilt还提供了2个预置Qualifier限定符@ActivityContext和@ApplicationContext
,可以直接作为@Provides
方法或@Inject
构造的参数使用。
class AnalyticsAdapter @Inject constructor(
@ActivityContext private val context: Context,
private val service: AnalyticsService
) { ... }
第三方组件注入
- @Provides
常用于被 @Module 注解标记类的内部方法上。并提供依赖项对象。
Hilt 支持最常见的 Android 类 Application、Activity、Fragment、View、Service、BroadcastReceiver 等等,但是您可能需要在Hilt 不支持的类中执行依赖注入,在这种情况下可以使用 @EntryPoint 注解进行创建,Hilt 会提供相应的依赖。
Hilt 中的组件(Compenent)、生命周期、作用域
使用 @Module 注解的类,需要使用 @Installin 注解来指定 module 的范围。
例如 @InstallIn(ApplicationComponent::class) 注解的 Module 就会绑定到 Application 的生命周期上。
Hilt 提供了以下组件来绑定依赖与对应 Android 类的活动范围
Hilt 组件 | 对应 Android 类活动的范围 |
---|---|
ApplicationComponent | Application |
ActivityRetainedComponent | ViewModel |
ActivityComponent | Activity |
FragmentComponent | Fragment |
ViewComponent | View |
ViewWithFragmentComponent | View annotated with @WithFragmentBindings |
ServiceComponent | Service |
Hilt 没有为 broadcast receivers 提供组件,因为 Hilt 直接进从 ApplicationComponent 中注入 broadcast receivers。
Hilt 会根据相应的 Android 类生命周期自动创建和销毁组件的实例,对应关系如下:
Hilt 提供的组件 | 创建对应的生命周期 | 结束对应的生命周期 | 作用域 |
---|---|---|---|
ApplicationComponent | Application#onCreate() | Application#onDestroy() | @Singleton |
ActivityRetainedComponent | Activity#onCreate() | Activity#onDestroy() | @ActivityRetainedScope |
ActivityComponent | Activity#onCreate() | Activity#onDestroy() | @ActivityScoped |
FragmentComponent | Fragment#onAttach() | Fragment#onDestroy() | @FragmentScoped |
ViewComponent | View#super() | View destroyed | @ViewScoped |
ViewWithFragmentComponent | View#super() | View destroyed | @ViewScoped |
ServiceComponent | Service#onCreate() | View destroyed | @ViewScoped |
在@InstallIn
模块中确定绑定范围时,绑定上的范围必须与component的范围匹配。例如,@InstallIn(ActivityComponent.class)
模块内的绑定只能用限制范围@ActivityScoped
。
例如我们需要在App中共享OkHttp的配置:
@Module
@InstallIn(ApplicationComponent::class)
class NetworkModule {
@Singleton
@Provides
fun provideOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.writeTimeout(20, TimeUnit.SECONDS)
.build()
}
}
默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例
ViewModel
各个类之间的依赖关系可以表示为图表,其中每个类都连接到其所依赖的类。所有类及其依赖关系的表示法便构成了应用图表。在图 1 中,您可以看到应用图表的抽象呈现。当 A 类 (ViewModel
) 依赖于 B 类 (Repository
) 时,有一条从 A 指向 B 的直线表示该依赖关系。
依赖项注入有助于建立这些链接并使您可以更换实现以进行测试。例如,在测试依赖于代码库的 ViewModel
时,您可以通过伪造或模拟传递 Repository
的不同实现,以测试不同的情形。
对于ViewModel这种常用Jetpack组件,Hilt专门为其提供了一种独立的依赖注入方式
dependencies {
...
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
}
class MyViewModel @ViewModelInject constructor(private val repository: Repository) : ViewModel() {
fun doWork() {
repository.doRepositoryWork()
}
}
参考资料:https://developer.android.google.cn/training/dependency-injection/hilt-android