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

Posted bug樱樱

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高相关的知识,希望对你有一定的参考价值。

依赖注入为何物

既然你已经点进来了,想必已经知道什么是依赖注入了吧,什么?!你还不知道什么是依赖注入吗,那你更要继续往下读了。

首先,来看看依赖注入的定义:

依赖注入就是参数传递

噢噢,我的老伙计,希望你并没有因为这个简单的定义而直接离开本文,我当然知道参数传递是每一位入门级程序员都掌握的基本能力,但为什么要用其他工具来完成这个参数传递呢,因为随着项目的膨胀,项目组件的不断扩大,组件之间的耦合关系也会愈发复杂,我们用一个实际例子来看看

项目膨胀导致的参数传递问题

假设我有一个这样的场景,我需要构造一个车子,车子又有其他零件,零件又有子零件。

/**
 * 车子
 */
class Car(
    private val steeringWheel: SteeringWheel,
    private val wheel: Wheel
)

/**
 * 方向盘
 */
class SteeringWheel(private val color:String)
/**
 * 轮子
 */
class Wheel(private val steel: Steel)

/**
 * 钢圈
 */
class Steel(private val circle:Int)
复制代码

那么我要如何构造这个车子呢,代码如下(多个场景表示在项目中存在多处需要构造Car的地方):

//模拟场景1
fun test1()
    Car(SteeringWheel("红色"), Wheel(Steel(30)))


//模拟场景2
fun test2()
    Car(SteeringWheel("蓝色"), Wheel(Steel(40)))


//模拟场景3
fun test3()
    Car(SteeringWheel("黑色"), Wheel(Steel(50)))

All right!所有的一切都没问题,项目正常上线,然后某天项目经理跟你说:嘿,这位码农,麻烦给钢圈加个花边吧。你按捺住内心想打人的冲动,然后打开AS,给钢圈加一个属性,不出意外的是,项目出现了一大堆报错,原来是因为汽车包含了轮子,轮子包含了花边,于是所有构造汽车的代码都报错了,于是你修改了代码,变成了如下:

/**
 * 钢圈
 */
class Steel(private val circle:Int,private val lace:String)

//模拟场景1
fun test1()
    Car(SteeringWheel("红色"), Wheel(Steel(30,"花边1")))


//模拟场景2
fun test2()
    Car(SteeringWheel("蓝色"), Wheel(Steel(40,"花边2")))


//模拟场景3
fun test3()
    Car(SteeringWheel("黑色"), Wheel(Steel(50,"花边3")))

加班到12点的你终于确认了所有的代码都被修改,提交测试上线,但是回到床位后的你依然战战兢兢的思考着今天的问题,万一下一次项目经理又要你添加其他属性呢,一想到又要加班熬夜你迅速起身疯狂百度,于是你了解到了工厂模式

于是你又起床新增了一个Car的工厂接口

interface CarFactory 
    fun build():Car


object CarAFactory:CarFactory
    override fun build(): Car 
        return Car(SteeringWheel("红色"), Wheel(Steel(30,"花边1")))
    



object CarBFactory:CarFactory
    override fun build(): Car 
        return Car(SteeringWheel("蓝色"), Wheel(Steel(40,"花边2")))
    



object CarCFactory:CarFactory
    override fun build(): Car 
        return Car(SteeringWheel("黑色"), Wheel(Steel(50,"花边3")))
    



//模拟场景1
fun test1()
    CarAFactory.build()


//模拟场景2
fun test2()
    CarBFactory.build()


//模拟场景3
fun test3()
    CarCFactory.build()

情况看起来好了很多,调用端已经没有具体的构造代码了,一切的构造都交给了工厂类,但是一旦这些类的属性膨胀起来后,会出现许许多多的工厂类,甚至工厂类本身都会出现属性配置,调用端的代码依然需要手动去修改,也许你进一步学习了抽象工厂,但是这些手段总给你一种感觉:面多了加水,水多了加面。此时的你迫切希望有一种更加解耦,更加无侵入性的手段帮你去实现对象的构建。

因此,假设有一个容器,他内部定义了如何构建各个零部件的构建方法,我们只需要告诉容器我需要什么,容器就会自动返回成品,因此我们也不需要手动去实现工厂类,那该多好?

因此,我隆重推荐谷歌Jetpack里面的组件------Hilt

为什么是Hilt?

如果你之前了解过安卓端依赖注入相关的框架,那么你肯定听过Okio,Dagger2,Hilt这三个框架,那么为什么选择Hilt呢,我的理由如下:

  1. Hilt基于Dagger2封装的框架,即在Dagger2的基础上加了一些安卓的场景化配置,也就是说,使用Hilt可以完成Dagger2的工作,同时避免了安卓场景下的部分模板代码。
  2. Hilt是Jetpack组件,和其他Jetpack组件协作良好,例如ViewModel,Compose,WorkManager都可以和Hilt无缝协作。

Hilt的初体验

给顶层的build.gradle添加插件

buildscript 
    ...
    dependencies 
        ...
        classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
    

给所有使用Hilt的Module对应的gradle添加如下配置:

apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

dependencies 
    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"

给项目的Application添加注解@HiltAndroidApp,添加这个注解的含义是给Application生成一个顶级容器,容器的生命周期跟随Application。

@HiltAndroidApp
class ExampleApplication : Application()  ... 

接下来,我们要给对应的android组件提供依赖(也就是对组件完成参数传递的),使用注解@AndroidEntryPoint,以Activity为例。

@AndroidEntryPoint
class ExampleActivity : AppCompatActivity()  ... 

然后,我们就可以给Activity注入我们想要的依赖了,例如注入一个Adapter,使用@Inject注释添加到我们想要注入的属性上面(切记,被注入的属性不能是private否则会报错)。

@AndroidEntryPoint
class ExampleActivity:AppCompatActivity() 

    //注入,不用手动实例化
    @Inject
    lateinit var analyticsAdapter: AnalyticsAdapter

    override fun onCreate(savedInstanceState: Bundle?) 
        super.onCreate(savedInstanceState)
        //直接调用对象,没有实例化代码
        analyticsAdapter.analytics()
    



class AnalyticsAdapter

    fun analytics()


非常神器,我们并没有看到adapter有被初始化的地方了,因为Hilt帮我们完成了初始化,也就是帮我们完成了Adapter的依赖注入!

然而当你满心欢喜的尝试去运行上面这段代码的时候,崩溃了!错误是analyticsAdapter并没有被正确实例化,这是什么原因呢,道理很简单:我们只是告诉了Hilt,我们需要一个AnalyticsAdapter,但是Hilt却并不知道AnalyticsAdapter该如何创建,解决问题也很简单,我们告诉Hilt如何创建它不就好了。

我们给AnalyticsAdapter的构造方法添加一个@Inject注释,告诉Hilt我们用空的构造方法来构建AnalyticsAdapter。

代码能运行了!

同时细心的发现代码左侧出现了两个小图标,这是一开始添加的插件的功能,点击一下AnalyticsAdapter对象左侧有红色向上箭头的图标,会发现跳转到了AnalyticsAdapter的构造函数;点击AnalyticsAdapter构造函数左侧的3个灰方块组成的小图标,则跳转到了AnalyticsAdapter对象。

上诉操作说明了当我们点击被注入的对象左侧的小图标的时候,实际上我们是在尝试“查找注入的来源”,当我们点击构造函数左侧的小图标的时候,实际上我们是在尝试“查找注入的去向”,通过这两个小图标我们可以快速查找到当前的对象是如何被注入的。

此刻,项目经理出现了,让我们添加某个功能,体现在代码中则是,Adapter需要外部传入一个对象,于是我们新增一个成员属性到AnalyticsAdapter的构造函数中去。

运行程序,不出意外的崩溃了。复盘原因,非常简单,因为我们告诉了Hilt如何创建AnalyticsAdapter,即使用它的带参构造函数去构建,但是Hilt在调带参构造函数的时候,发现自己不懂如何创建NetworkService。

参考当初构建AnalyticsAdapter的方式,我们继续给NetworkService的构造参数也添加一个@Inject注解,熟悉的图标又出现了,Hilt这回懂得了如何正确创建NetworkService。

运行代码,正确!好的,刚才给Adapter新增了一个成员属性,让我们再看看Activity的代码,完全没有发生变化。

我们通过了Hilt来帮我们完成了参数的传递(注意,只是辅助完成了这个过程并不是消灭了参数传递),对于Activity来说,他只是需要Adapter,他并不在乎Adapter的内部构建过程,所以Adapter内部再怎么发生剧烈的变化,Activity的代码都是不用去修改的,非常的完美。

课后小练习

下面提供两个小练习让你去体验使用Hilt实现依赖注入的低耦合性

1.给AnalyticsAdapter扩充第二个成员变量,类型为你自己定义的类(可以参考NetworkService)

2.给NetworkService增加一个成员变量

好了,本文到此就结束,关于Hilt的话题我们才刚刚起步,还有许多问题等待着我们去解决,例如如何注入一个接口?那些我们不能修改代码的第三方类如何注入(因为不能修改构造函数)?如何保证注入的都是同一个对象(实现单例)?那么下期我将更详细地逐一解决这些问题。

作者:晴天小庭
链接:https://juejin.cn/post/7123148433367498766

最后

如果想要成为架构师或想突破20~30K薪资范畴,那就不要局限在编码,业务,要会选型、扩展,提升编程思维。此外,良好的职业规划也很重要,学习的习惯很重要,但是最重要的还是要能持之以恒,任何不能坚持落实的计划都是空谈。

如果你没有方向,这里给大家分享一套由阿里高级架构师编写的《Android八大模块进阶笔记》,帮大家将杂乱、零散、碎片化的知识进行体系化的整理,让大家系统而高效地掌握Android开发的各个知识点。

相对于我们平时看的碎片化内容,这份笔记的知识点更系统化,更容易理解和记忆,是严格按照知识体系编排的。

一、架构师筑基必备技能

1、深入理解Java泛型
2、注解深入浅出
3、并发编程
4、数据传输与序列化
5、Java虚拟机原理
6、高效IO
……

二、Android百大框架源码解析

1.Retrofit 2.0源码解析
2.Okhttp3源码解析
3.ButterKnife源码解析
4.MPAndroidChart 源码解析
5.Glide源码解析
6.Leakcanary 源码解析
7.Universal-lmage-Loader源码解析
8.EventBus 3.0源码解析
9.zxing源码分析
10.Picasso源码解析
11.LottieAndroid使用详解及源码解析
12.Fresco 源码分析——图片加载流程

三、Android性能优化实战解析

  • 腾讯Bugly:对字符串匹配算法的一点理解
  • 爱奇艺:安卓APP崩溃捕获方案——xCrash
  • 字节跳动:深入理解Gradle框架之一:Plugin, Extension, buildSrc
  • 百度APP技术:Android H5首屏优化实践
  • 支付宝客户端架构解析:Android 客户端启动速度优化之「垃圾回收」
  • 携程:从智行 Android 项目看组件化架构实践
  • 网易新闻构建优化:如何让你的构建速度“势如闪电”?

四、高级kotlin强化实战

1、Kotlin入门教程
2、Kotlin 实战避坑指南
3、项目实战《Kotlin Jetpack 实战》

  • 从一个膜拜大神的 Demo 开始

  • Kotlin 写 Gradle 脚本是一种什么体验?

  • Kotlin 编程的三重境界

  • Kotlin 高阶函数

  • Kotlin 泛型

  • Kotlin 扩展

  • Kotlin 委托

  • 协程“不为人知”的调试技巧

  • 图解协程:suspend

五、Android高级UI开源框架进阶解密

1.SmartRefreshLayout的使用
2.Android之PullToRefresh控件源码解析
3.Android-PullToRefresh下拉刷新库基本用法
4.LoadSir-高效易用的加载反馈页管理框架
5.Android通用LoadingView加载框架详解
6.MPAndroidChart实现LineChart(折线图)
7.hellocharts-android使用指南
8.SmartTable使用指南
9.开源项目android-uitableview介绍
10.ExcelPanel 使用指南
11.Android开源项目SlidingMenu深切解析
12.MaterialDrawer使用指南

六、NDK模块开发

1、NDK 模块开发
2、JNI 模块
3、Native 开发工具
4、Linux 编程
5、底层图片处理
6、音视频开发
7、机器学习

七、Flutter技术进阶

1、Flutter跨平台开发概述
2、Windows中Flutter开发环境搭建
3、编写你的第一个Flutter APP
4、Flutter开发环境搭建和调试
5、Dart语法篇之基础语法(一)
6、Dart语法篇之集合的使用与源码解析(二)
7、Dart语法篇之集合操作符函数与源码分析(三)

八、微信小程序开发

1、小程序概述及入门
2、小程序UI开发
3、API操作
4、购物商场项目实战……

全套视频资料:

一、面试合集

二、源码解析合集


三、开源框架合集


欢迎大家一键三连支持,若需要文中资料,直接点击文末CSDN官方认证卡片免费领取↓↓↓

以上是关于使用Hilt完成依赖注入,让你的安卓代码层次有几层楼那么高的主要内容,如果未能解决你的问题,请参考以下文章

Hilt 稳定版发布 | 更便捷的 Android 依赖项注入

在 Android 中通过 Hilt 进行依赖项注入

Kotlin 中使用 Hilt 的开发实践

Kotlin 中使用 Hilt 的开发实践

Android Hilt依赖注入框架

在 Android 中通过 Hilt 进行依赖项注入