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

我正在参加「掘金·启航计划」

上一篇文章的快捷入口:写文章 – 使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高(三) – 掘金 (juejin.cn)

辅助注入

如果通过看前面的文章学会了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
)
data class Wheel(
    val name:String
)

data class Engine(
    val name:String
)



class Car(
    val wheel:Wheel,
    val engine:Engine,
    val number:Int
)
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 = ???
)
}
}
@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 = ???
        )
    }

}
@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
)
class Car @AssistedInject constructor(


    val wheel:Wheel,


    val engine:Engine,


    @Assisted

    val number:Int
)
class Car @AssistedInject constructor( val wheel:Wheel, val engine:Engine, @Assisted val number:Int )

二、构建工厂类,使用@AssistedFactory注解表示这是一个辅助注入工厂类,同时编写需要注入的实体类的构建方法,方法只需要动态传入的参数,在这里指的是number

@AssistedFactory
interface JiLiCarFactory{
fun createJiLiCar(
number:Int
):Car
}
@AssistedFactory

interface JiLiCarFactory{

    
    fun createJiLiCar(

        number:Int
    ):Car
    

}
@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)
}
}
@AndroidEntryPoint
class YouFragment : Fragment() {


    //注入工厂类
    @Inject
    private lateinit var jiLiCarFactory: JiLiCarFactory
    

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        //使用工厂类,传入动态参数构建具体的对象
        val jiLiCar: Car =jiLiCarFactory.createJiLiCar(114514)
    }
    
}
@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
)
class Car @AssistedInject constructor(


    val wheel:Wheel,


    val engine:Engine,


    @Assisted

    val number:Int,

    @Assisted
    val number2:Int

)
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
)
class Car @AssistedInject constructor(


    val wheel:Wheel,


    val engine:Engine,


    @Assisted("number")
    val number:Int,

    @Assisted("number2")
    val number2:Int

)
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
}
@AssistedFactory

interface JiLiCarFactory{



    fun createJiLiCar(

        @Assisted("number") number:Int,
        @Assisted("number2") number2:Int
    ):Car

}
@AssistedFactory interface JiLiCarFactory{ fun createJiLiCar( @Assisted("number") number:Int, @Assisted("number2") number2:Int ):Car }

工厂类用法和原来的保持一致,只是多加了参数

val jiLiCar=jiLiCarFactory.createJiLiCar(114514,1111)
val jiLiCar=jiLiCarFactory.createJiLiCar(114514,1111)
val jiLiCar=jiLiCarFactory.createJiLiCar(114514,1111)

总结

好的,关于Hilt的系列就到此结束了,笔者写这系列的初衷是帮助那些刚刚使用Hilt的新手快速入门并动手使用Hilt,并没有做太深入的分析(笔者的程度也没有到那个层次,就不班门弄斧了),同时也为很久没有更新文章抱歉,近期会恢复更新频率,同时也会谈谈compose相关的话题,敬请期待。

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYJYMpH1' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片