为什么是Hilt?
如果你之前了解过安卓端依赖注入相关的框架,那么你肯定听过Okio,Dagger2,Hilt这三个框架,那么为什么选择Hilt呢,我的理由如下:
- Hilt基于Dagger2封装的框架,即在Dagger2的基础上加了一些安卓的场景化配置,也就是说,使用Hilt可以完成Dagger2的工作,同时避免了安卓场景下的部分模板代码。
- 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的话题我们才刚刚起步,还有许多问题等待着我们去解决,例如如何注入一个接口?那些我们不能修改代码的第三方类如何注入(因为不能修改构造函数)?如何保证注入的都是同一个对象(实现单例)?那么下期我将更详细地逐一解决这些问题。