如果没了解过Dagger,那就直接开始学Hilt吧,比Dagger容易上手使用,而且Hilt是基于Dagger2开发的。
在开始学习之前,先搞清楚为什么要用它,能带来什么好处?
作用:解耦
之前有说过APT(annotation processing tool)也有解耦的作用,通过自定义注解,获取到被注解的类/方法/变量信息,从而实现在两个独立的Module之前实现Activity跳转的功能。
关系:Hilt的实现依赖APT技术
Hilt可以通过注解的方式将所需对象传入到另一个类当中,避免了我们自己new对象,但前题是要告诉Hilt怎么去创建对象。
所以学习Hilt,就是告诉Hilt怎么去创建我们所需的对象
补充一点:在一个类中使用另外的对象,通常要怎么get到它?
- new 对象
- 构造方法传参
这两种引用方式都可通过Hilt提供的@Inject注解来实现。
Ok,接下来配置Hilt的使用环境:
- 工程级gradle下引入hilt插件:
buildscript {
ext {
compose_version = '1.2.0'
}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
...
id 'com.google.dagger.hilt.android' version '2.44' apply false //引入Hilt插件
}
- 项目级gradle下,引入kapt和Hilt插件
plugins {
...
//在项目级gradle中引入以下两个插件
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
- 在项目依赖中引入Hilt
dependencies {
...
implementation "com.google.dagger:hilt-android:2.44"
kapt "com.google.dagger:hilt-compiler:2.44"
}
- 允许引用来生成代码。与android{}平级写入
// Allow references to generated code
kapt {
correctErrorTypes true
}
通过以上4步,就将使用Hilt的环境配置完毕。
使用之前,首先用@HiltAndroidApp
对Application进行注解,相当于Hilt的初始化吧
@HiltAndroidApp
class MyApplication: Application(){
}
同样的,如果要在
Activity
Fragment
Service
Broadcast
View
中使用,也都需要对类先进行注解,不过注解名称与Applicaion不同:@AndroidEntryPoint
Hilt的一些用法
- 自有类的引入:
//对于普通类,直接通过在构造方法添加@Inject来注入
class MyTest @Inject constructor() {
fun print(): Unit {
Log.i(">>>", "直接通过构造方法来注入,获取实例!")
}
}
可以明显看到,用@Inject注解修饰了主构造方法,这就告诉Hilt,用该构造方法来创建该类的对象供其他地方调用。
在Activity中要引用该类实例时,同样用@Inject注解成员变量:
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var myTest: MyTest
override fun onCreate(savedInstanceState: Bundle?) {
...
myTest.print()
}
}
- 如果成员变量或构造入参的类型是一个接口或抽象类呢?其实说的意思是没有构造方法用来注解,那只能注解子类的构造方法并提供其实现类了。所以有两步需要做:
- 提供其注解构造方法的子类(实现类);
- 告诉Hilt用这个实现类的构造方法提供实例。(因为被注解构造方法的子类可能有多个,要从中选其一)
interface MyInterface {
fun print()
}
class MyInterfaceImpl @Inject constructor() : MyInterface {
override fun print() {
Log.i(">>>", "接口类型完成注入")
}
}
@Module
@InstallIn(ActivityComponent::class)
abstract class InterfaceModule {
@Binds
abstract fun bindMyInterface(
myInterfaceImpl: MyInterfaceImpl
): MyInterface
}
这里有3个新出现的注解:
@Module 告诉Hilt从这里获取实例对象
@InstallIn 管理可现范围
@Binds 绑定接口与某个自有子类,可以用@Inject注解构造方法。
在Activiy中的调用和之前一样,直接用@Inject注解变量:
@AndroidEntryPoint
class MainActivity : ComponentActivity() {
@Inject lateinit var myInterface: MyInterface
override fun onCreate(savedInstanceState: Bundle?) {
...
myInterface.print()
}
}
- 非自己写的类,我们无法注解其构造方法,这种情况下,我们无法绑定接口与其子类,也就是不再使用@Binds,而是直接提供其对象,使用@provides注解方法,类名/方法名没有要求,通俗易懂就好:
@Module
@InstallIn(ActivityComponent::class)
object DependOnYouModule {
@Provides
fun providesAInstance(): Retrofit {
...
return retrofitInstance
}
}
小结一下:
不管怎么写,其实就是要让Hilt知道怎样提供一个被注解后所需要的实例。