上一篇文章的快捷进口:运用Hilt完结依靠注入,让你的安卓代码层次有几层楼那么高(一) – ()
运用Hilt注入不能修正结构办法的类
在上一节中,在向Hilt阐明怎么注入需求的类的时分,咱们是通过直接修正类的结构办法的办法来完结的,那么实践开发中存在多种情况,是咱们无法修正结构办法的,那么怎么完结这个使命呢?答案是自定义咱们的模块,这儿的模块指的是带有@Module注释的类,这个模块的含义跟@Inject注释加在结构函数中的含义是相同的,都是向Hilt阐明注入目标的办法。
1.注入一个接口(Bind办法)
假设一个这样的场景,activity需求运用一个TestInterface的接口实例,完结则来自TestImpl,按照第一章的办法,咱们无法运用@Inject去修饰接口的结构参数,由于接口底子没有结构参数。
@AndroidEntryPoint
class ExampleActivity:AppCompatActivity() {
@Inject
lateinit var testInterface: TestInterface
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
testInterface.doSomeThing()
}
}
interface TestInterface{
fun doSomeThing()
}
//接口完结
class TestImpl:TestInterface{
override fun doSomeThing() {
Log.d("日志","做了一些事")
}
}
于是,咱们新建一个Hilt容器,运用@Module注解,留意容器有必要是笼统类。然后咱们新建一个办法,办法也有必要是笼统办法,办法运用@Bind注解,办法参数为接口的完结,办法的返回值为咱们需求注入的办法。
@Module
//引证生成在Activity上的组件,关于这个后续文章细讲
@InstallIn(ActivityComponent::class)
abstract class TestModule {
@Binds
abstract fun bindTestInterface(
//接口的实例
testImpl: TestImpl
): TestInterface //需求绑定的接口
}
写完容器之后,接口左边代码的位置出现了咱们熟悉的小图标,点击图标,发现跳转的正是咱们刚刚完结的容器的代码块区域,这反映了接口的注入源是咱们自己完结的容器。

2.注入一个不能修正的类(Provide办法)
不能修正的类是什么意思呢,也就是说不是本项目创造的类,咱们并不能直接修正其结构办法,例如String、okhttp、Gson等,和注入接口相同,咱们相同是创造Hilt容器的办法,和注入接口有点不同,容器不能是笼统类,由于咱们需求详细的办法体,办法运用@Provide注解。
办法的参数是构建当时目标需求的其他依靠(待会会讲),办法的返回值是咱们要注入的类型,办法体则是注入的办法,下面以okhttpClient为比如。
@AndroidEntryPoint
class ExampleActivity:AppCompatActivity() {
@Inject
lateinit var okHttpClient: OkHttpClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
}
@Module
@InstallIn(ActivityComponent::class)
object OkHttpClientModule{
@Provides
fun provideOkHttpClient():OkHttpClient{
return OkHttpClient()
}
}
方才上面提到了,Provide办法的参数是构建当时目标需求的其他依靠,这是怎么了解呢,例如咱们在构建OKhttpClient的时分,肯定是需求其他参数的,咱们以cookiejar为比如展现怎么在Provide办法中传入其他参数。
假设咱们有一个这样的CookieJar,咱们需求把他传入到OKhttpClient结构进程中去,首要咱们需求向Hilt声明怎么构建一个CookieJar实例,依据第一章以及第二章的内容,咱们有三种办法来完结:
1.在结构函数上增加一个注解
2.运用Binds办法
3.运用Provides办法
//需求被注入到OkHttpClient中的CookieJar实例
class TestCookiejar : CookieJar{
override fun loadForRequest(url: HttpUrl): List<Cookie> {
TODO("Not yet implemented")
}
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>) {
TODO("Not yet implemented")
}
}
下面将别离演示三种办法的代码:
1.结构函数上增加注解
class TestCookiejar @Inject constructor(): CookieJar{
//...略
}
2.Binds办法
@Module
@InstallIn(ActivityComponent::class)
abstract class CookieJarModule{
@Binds
abstract fun bindsCookieJar(testCookiejar: TestCookiejar):CookieJar
}
3.Provides办法
@Module
@InstallIn(ActivityComponent::class)
object CookieJarModule2{
@Provides
fun providesCookieJar():CookieJar{
return TestCookiejar()
}
}
你能够挑选以上任意一种,他们的意图都只要一个:向Hilt阐明你要怎么构建一个CookieJar的实例,挑选其间一个放入到代码中,然后咱们回到OkHttpClient的容器代码中,在办法中增加一个CookieJar参数。

增加了参数之后,参数左边又出现了一个小图标,阐明办法中的这个参数已经成功被容器提供了,一切都不需求咱们手动传入,只需求向Hilt阐明即可。相同的,咱们回到OkHttpClient在Activity是怎么被获取的。

没有发生任何改变!由于咱们只需求告知Hilt:我要在某个Activity中获取一个OkHttpClient,一切的都交给Hilt即可,哪怕OkHttpClient的构建进程发生了改变(例如新增了一个CookieJar),关于最上层的获取者(Activity)来说,都是无感的,十分的轻耦合!
一个类,多种注入办法
上述的多种注入办法都存在一个问题,咱们只能对一个类注入一种实例,例如OkHttpClient只能存在一种,可是实践项目中或许存在多套Client,亦或者是更常见的String,咱们总不能只能注入一个String目标吧,因而咱们需求告知Hilt怎么区分它们。
办法一:运用Named注解
十分的简略,只需求在Provides办法的容器的办法中增加一个注解Named,然后写上绝无仅有的Tag,在运用端一起加上对应的Tag,这样Hilt注入的时分就会挑选对应的注入办法,为同一个类型提供多种绑定。
@AndroidEntryPoint
class ExampleActivity:AppCompatActivity() {
@Inject
@Named("One")
lateinit var oneString:String
@Inject
@Named("Two")
lateinit var twoString:String
}
@Module
@InstallIn(ActivityComponent::class)
object StringModule{
@Provides
@Named("One")
fun providesOneString():String{
return "One"
}
@Provides
@Named("Two")
fun providesTwoString():String{
return "Two"
}
}
注入接口也是相同的道理,在对应的binds办法中增加Named注解即可,你能够自己动手试试
办法二:自定义注解
首要笔者说下自己的态度,笔者并不喜爱第一种办法是由于Named注解里边的值只能硬编码,由于注解的特性并不能传入一个静态的String,因而容易写错或者后期重构容易遗失修正导致出现注入失利,因而笔者更喜爱这种办法。
首要依据你需求的分类定义相应的注解,注解都增加@Qualifier(告知Hilt这个注解是分类器)
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OneString
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class TwoString
其他的部分和Named差不多
@AndroidEntryPoint
class ExampleActivity:AppCompatActivity() {
@Inject
@OneString
lateinit var oneString:String
@Inject
@TwoString
lateinit var twoString:String
}
@Module
@InstallIn(ActivityComponent::class)
object StringModule{
@Provides
@OneString
fun providesOneString():String{
return "One"
}
@Provides
@TwoString
fun providesTwoString():String{
return "Two"
}
}
好了,这篇文章到这儿就结束了,下一期咱们持续探讨一下Hilt的容器生命周期和容器作用域相关的话题,特别是怎么让注入的目标单例化。