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中限定符和效果域常识。