上一篇文章的快捷进口:运用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 //需求绑定的接口
}

  写完容器之后,接口左边代码的位置出现了咱们熟悉的小图标,点击图标,发现跳转的正是咱们刚刚完结的容器的代码块区域,这反映了接口的注入源是咱们自己完结的容器。

使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(二)

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完成依赖注入,让你的安卓代码层次有几层楼那么高(二)

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

使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(二)

  没有发生任何改变!由于咱们只需求告知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的容器生命周期和容器作用域相关的话题,特别是怎么让注入的目标单例化。

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。