辅助注入
如果通过看前面的文章学会了Hilt的基础使用,那么恭喜你,你基本已经可以在项目中展开使用Hilt框架为你的项目提供自动注入功能了,但是有一些场景你可能会感到疑惑,回顾之前的注入,你会发现一个问题:当使用Hilt构建一个对象的时候,在定义对象的时候,就要求所有参数已经被确定
,但是实际场景中,我们有许多参数是无法在定义对象的阶段就被确定的,一些参数需要在项目运行时才能被确定,例如网络请求的结果等,这些动态的参数让我们无法使用Hilt为我们注入,至少目前还不行。
为了解决这些动态参数导致的问题,dagger2(即Hilt的底层框架)提供了一种解决问题的方案:辅助注入
。
辅助注入是一种依赖注入 (DI) 模式,用于构造一个对象,其中一些参数可能由 DI 框架提供,而其他参数必须在创建时由用户传入(也称为“辅助”)。 工厂通常负责组合所有参数并创建对象。
依然是废话不多说环节,我们使用具体的案例来讲解如何使用辅助注入
data class Wheel( val name:String ) data class Engine( val name:String ) class Car( val wheel:Wheel, val engine:Engine, val number:Int )
假设我们有轮子、引擎和汽车三个实体类,其中汽车是由轮子和引擎组成的,我们希望创建一个工厂,自动为我们生成某个类型的汽车,因此轮子和引擎的构建方式是固定的,但是汽车的编号每个汽车是不同的。
按照之前的文档,我们编写Module类,但是我们会发现,我们无法在定义provides方法阶段就定义好number。
@InstallIn(SingletonComponent::class) @Module object JiLiCarModule{ @Singleton @Provides fun provideJiLiWheel():Wheel{ return Wheel("吉利牌车轮") } @Singleton @Provides fun provideJiLiEngine():Engine{ return Engine("吉利牌引擎") } @Provides fun provideJiLiCar( wheel: Wheel, engine: Engine ):Car{ return Car( wheel = wheel, engine = engine, //👇🏻出问题的部分,我们无法明确这个编号 number = ??? ) } }
也许某些情况下,我们确实能在定义provides方法的时候就明确number的生成方式(例如随机数的业务场景),但是我们要讨论的是在定义provides方法阶段无法明确参数
的情况,因此我们需要dagger提供的辅助注入
来帮助我们完成这种场景下的Hilt注入。
动手实战
一、为汽车实体类添加@AssistedInject
注解,同时为动态传入的参数添加@Assisted
注解,这里是number。
class Car @AssistedInject constructor( val wheel:Wheel, val engine:Engine, @Assisted val number:Int )
二、构建工厂类,使用@AssistedFactory
注解表示这是一个辅助注入工厂类,同时编写需要注入的实体类的构建方法,方法只需要动态传入的参数
,在这里指的是number
@AssistedFactory interface JiLiCarFactory{ fun createJiLiCar( number:Int ):Car }
三、注入工厂类,这里和之前直接注入对象使用方法基本是一致的,区别只有一个,这里注入的是工厂
@AndroidEntryPoint class YouFragment : Fragment() { //注入工厂类 @Inject private lateinit var jiLiCarFactory: JiLiCarFactory override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //使用工厂类,传入动态参数构建具体的对象 val jiLiCar: Car =jiLiCarFactory.createJiLiCar(114514) } }
四、解决相同类型参数注入问题
当你有多个相同类型的参数的时候,Hilt会不知道如何注入,例如我们的实体类是这样的情况:
class Car @AssistedInject constructor( val wheel:Wheel, val engine:Engine, @Assisted val number:Int, @Assisted val number2:Int )
这里出现了两个相同类型(Int)的参数,因此我们需要区分开来,这里使用注解@Assisted的参数来区分,改造为如下:
class Car @AssistedInject constructor( val wheel:Wheel, val engine:Engine, @Assisted("number") val number:Int, @Assisted("number2") val number2:Int )
同时别忘了为工厂的方法也添加对应的注解,否则Hilt一样无法知道如何映射对应的参数
@AssistedFactory interface JiLiCarFactory{ fun createJiLiCar( @Assisted("number") number:Int, @Assisted("number2") number2:Int ):Car } 工厂类用法和原
来的保持一致,只是多加了参数
val jiLiCar=jiLiCarFactory.createJiLiCar(114514,1111)
总结
好的,关于Hilt的系列就到此结束了,笔者写这系列的初衷是帮助那些刚刚使用Hilt的新手快速入门并动手使用Hilt,并没有做太深入的分析(笔者的程度也没有到那个层次,就不班门弄斧了),同时也为很久没有更新文章抱歉,近期会恢复更新频率,同时也会谈谈compose相关的话题,敬请期待。