Hilt 是 Android 的依赖项注入库,可减少在项目中执行手动依赖项注入的样板代码。
Android Studio环境为 Android Studio Flamingo | 2022.2.1
Hilt最新版本为2.46
添加Hilt
首先在根目录的build.gradle
中添加Hilt
插件:
plugins {
...
id 'com.google.dagger.hilt.android' version '2.46' apply false
}
然后在app/build.gradle
中添加Hilt
依赖:
plugins {
// kotlin需要增加kapt
id 'kotlin-kapt'
id 'com.google.dagger.hilt.android'
}
android {
...
// hilt使用Java 1.8,创建工程默认已经添加
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation "com.google.dagger:hilt-android:2.46"
kapt "com.google.dagger:hilt-compiler:2.46"
}
至此我们就可以体验Hilt
的功能了。
简单使用Hilt
未使用Hilt之前
在未使用Hilt
之前,如果我们想要在Activity
中构造一个类,一般的我们直接使用类的构造方法来创建
class HiltActivity : BaseActivity<ActHiltBinding>() {
private val test = Test()
override fun initViewBinding() = ActHiltBinding.inflate(layoutInflater)
override fun onResume() {
super.onResume()
test.print()
}
}
class Test {
fun print() {
Log.d("Test", "print: Test")
}
}
这是我们常规注入一个类的操作,每次都需要使用构造方法来创建对象,然后通过对象来调用其公共方法。
接下来看看使用Hilt
之后如何来构造一个类
使用Hilt之后
Hilt
要求使用的App
必须包含一个带有@HiltAndroidApp
注解的Application
类
@HiltAndroidApp
class HiltApplication : Application() {
}
# AndroidManifest
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".HiltApplication">
</application>
</manifest>
记得在Manifest
中声明我们自定义的HiltApplication
注入无参对象
如果我们想在Activity
中使用Hilt
来构造其它类的时候,需要在Activity
类上添加@AndroidEntryPoint
注解,此注解会生成一个单独的Hilt
组件,然后我们就可以在类中使用@Inject
注解执行注入操作了,具体看下面代码:
/**
* @description
* @author Taonce.
* @date 2023/5/10/22:13
*/
@AndroidEntryPoint
class HiltActivity : BaseActivity<ActHiltBinding>() {
@Inject
lateinit var hiltTest: HiltTest
override fun initViewBinding() = ActHiltBinding.inflate(layoutInflater)
override fun onResume() {
super.onResume()
hiltTest.print()
}
}
class HiltTest @Inject constructor() {
fun print() {
Log.d("HiltTest", "print: HiltTest")
}
}
HiltTest
是一个无参的类,需要在此构造方法之前加上@Inject
,此操作就是告诉Hilt
是如何来创建此对象;
然后在Activity
中就可以使用@Inject lateinit var hiltTest: HiltTest
来声明对象了,对象不可以使用val
关键字,一定要lateinit var
来修饰。
注入有参对象
看完上面这种无参类之后,是不是有个疑问,如果HiltTest
是一个有参构造方法怎么办,Hilt
是不是也可以直接创建呢?答案是否,有参数的构造方法我们也是需要告诉Hilt
此参数如何来创建,请看下面代码:
@AndroidEntryPoint
class HiltActivity : BaseActivity<ActHiltBinding>() {
@Inject
lateinit var hiltTestParams: HiltTestParams
override fun initViewBinding() = ActHiltBinding.inflate(layoutInflater)
override fun onResume() {
super.onResume()
hiltTestParams.print()
}
}
class HiltTestParams @Inject constructor(
private val params: Params
) {
fun print() {
params.print()
}
}
class Params @Inject constructor() {
fun print() {
Log.d("HiltParams", "print: HiltParams")
}
}
这里我们想通过Hilt
帮忙注入一个HiltTestParams
实例,它是一个带有Params
参数的构造方法,并且Params
对象在构造方法之前也加上了@Inject
注解,这样Hilt
就可以一步一步得到所有的信息。
注入三方对象
到这一步我们可以使用Hilt
来注入自己定义的类,如果我们想注入三方类咋办呢?我们不可以直接在三方类的构造方法中加入@Inject
注解呢(或者三方类实例不可以直接使用构造方法来创建)…Hilt
还有一种方法帮助我们注入这种类型的类,下面以Retrofit
举例看看是如何注入的。
@Module
@InstallIn(ActivityComponent::class)
object RetrofitProvider {
@Provides
fun providerRetrofit(): Api {
return Retrofit.Builder()
.baseUrl("https://www.wanandroid.com")
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(Api::class.java)
}
}
@AndroidEntryPoint
class RetrofitActivity : BaseActivity<ActRetrofitBinding>() {
@Inject
lateinit var api: Api
override fun initViewBinding() = ActRetrofitBinding.inflate(layoutInflater)
override fun onResume() {
super.onResume()
lifecycleScope.launch {
val article = api.article()
Log.d("RetrofitActivity", "Retrofit article: $article")
}
}
}
Hilt
提供了Module
模块帮助我们提供注入的一些信息,它会向Hilt
告知如何提供某些类型的实例,并且Module
必须使用@InstallIn
注解来告知Hilt
此模块将作用于哪个Android
类中,@InstallIn
作用于见下图
Hilt 组件 | 注入器面向的对象 |
SingletonComponent | Application |
ActivityRetainedComponent | 不适用 |
ViewModelComponent | ViewModel |
ActivityComponent | Activity |
FragmentComponent | Fragment |
ViewComponent | View |
ViewWithFragmentComponent | 带有 @WithFragmentBindings 注解的 View |
ServiceComponent | Service |
providerRetrofit()
方法的返回对象是一个Api
实例,并且方法用@Provides
来注解,此注解就是告诉Hilt
每当需要使用Api
实例的时候,都是通过此方法来注入创建。
注入接口实例
接口是没有办法直接通过构造方法来创建它的实例的,Hilt
提供了@Binds
方式帮助我们住一个一个接口的实例,具体看下面实现代码
interface ApiService {
fun doSomething()
}
class ApiServiceImpl @Inject constructor() : ApiService {
override fun doSomething() {
Log.d("ApiServiceImpl", "doSomething")
}
}
@Module
@InstallIn(SingletonComponent::class)
interface AppModule {
@Binds
fun bindApiService(apiServiceImpl: ApiServiceImpl): ApiService
}
ApiService
是一个接口,bindApiService()
方法帮助我们自动生成它的实例对象,需要通过@Binds
来进行注解,并且传参是它的具体实现实例
通过上述代码我们就可以直接使用@Inject
来引用此对象了
@AndroidEntryPoint
class InterfaceActivity : BaseActivity<ActHiltBinding>() {
@Inject
lateinit var apiService: ApiService
override fun initViewBinding(): ActHiltBinding {
return ActHiltBinding.inflate(layoutInflater)
}
override fun onResume() {
super.onResume()
apiService.doSomething()
}
}
结尾
导致为止,我们就可以使用Hilt
来注入一些平时高频的实例,后面会接着说明Hilt
中限定符和作用域知识。