Dependency injection

谈到 Android 的 dependency injection (DI),大家一定会想到 Dagger 这个 DI library。因为 Dagger 2 是由 Google 开发,加上在 Android Developers 网站有对应的教学文章,所以成为不二之选。不过 Dagger 向来都有难学的印象,尤其是在以前 Dagger 2 网站那个恶名昭彰的咖啡机教学。本来用咖啡机来说明 DI 的概念就没有甚麽大问题,问题在於看完那个咖啡机类比是不会知道如何在 Android app 上套用那些概念和 Dagger 提供的功能。或许大家读电脑科学/计算机科学/资讯工程之类的课程时都有学过 DI 但还是不能顺利地用 Dagger,这是因为 Android 那些组件的 constructor 不是由我们去 call,结果要在 onCreate 之类的 callback 加上 DI library 要我们写的 code 才能拿到我们要用的 dependency。

Google 曾经推出过 Dagger Android 的 library,就是方便在 Android 开发时使用 Dagger。留意 Dagger 本身并不是只为 Android 设计,它本来是一个通用的 DI library。但推出後有些人发觉它甚至比原装 Dagger 更难用。所以他们做了一个替代品:Dagger Hilt。其实 Dagger Hilt 就是把 Dagger 在 Android 的用法标准化,本来在 Dagger 一些由我们去定义的东西在 Dagger Hilt 变成由 Hilt 提供,我们要按照 Hilt 规定的方式做 DI。其中一个例子是 component 改为由 Hilt 按 Android 各部件的 lifecycle 预先安排好的 componen。再加上 Hilt 的 Gradle plugin 和 Android Jetpack library 的配合,这样就可以将平时用 Dagger 要写的一大堆 boilerplate code 大大减少,而且在进入新的开发团队时不用再浪费时间理解那些 AppCompoent@Singleton 的实际意义。

现在讨论 Dagger Hilt 没有实际 code 做示范,感觉比较虚无,我们会在之後用到 Dagger Hilt 时再作讲解。在结束本篇之前,相信大家心入面都会问一个问题:为甚麽要用 DI library。或许有不少人都是为用而用,或者是因为面试会问到所以要学习这些 library。我觉得最易理解为甚麽要用 DI 就是试试找一个没有写过单元测试 (unit test) 的项目把一些现有的 class 为它们写单元测试,当你发现困难重重时(例如用了太多 singleton、很多地方写死了在 unit test 很难换走导致很多情景无法制造出来)就会开始明白为甚麽要用 DI library。不过不用担心,这次的示范 app 本身就有考虑到 unit testing 来写的,我们会在下一篇开始用 Dagger Hilt。

准备工作

在最顶层的 build.gradle 和 app module 的 build.gradle 加上 Dagger Hilt 的 Gradle plugin 和 Dagger Hilt 相关的 dependency。

// root level build.gradle
buildscript {
    ext.daggerVersion = '2.38.1'
    repositories {
        google()
        mavenCentral()
    }
    dependencies {
        // ...
        classpath "com.google.dagger:hilt-android-gradle-plugin:$daggerVersion"
    }
}
// app module build.gradle
implementation "com.google.dagger:hilt-android:$daggerVersion"
kapt "com.google.dagger:hilt-compiler:$daggerVersion"
testImplementation "com.google.dagger:hilt-android-testing:$daggerVersion"
testAnnotationProcessor "com.google.dagger:hilt-compiler:$daggerVersion"
androidTestImplementation "com.google.dagger:hilt-android-testing:$daggerVersion"
androidTestAnnotationProcessor "com.google.dagger:hilt-compiler:$daggerVersion"

然後为自行 extend 出来的 Application 加上 Dagger Hilt 的 annotation。不要忘记在 manifest 的 application tag 加上 name attribute。

@HiltAndroidApp
class EtaDemoApp : Application() {
    override fun onCreate() {
        super.onCreate()
    }
}

小结

  • Dagger Hilt 是建基於 Dagger 的 library,它就是为 Android 开发时用 Dagger 提供了一个固定的范式
  • Dagger Hilt 有 Gradle plugin 能减少平常用 Dagger 时所写的 boilerplate code,加上其他 Jetpack library 的配套令我们用 Dagger 更自然(令人感觉上更似 dependency injection 而不是 service locator
  • 用 DI library 很大部分的原因是为了方便写 unit test 时能把依赖的组件换成其他东西,这样就能测试到不同的场景

补充资料


<<:  MySQL学习_Day4

>>:  Day20 - 铁人付外挂设定介面(二)- 全域设定

反馈与「大便三明治」

这篇我是在讨论提供反馈 (giving feedback)。但对主管来说,如何接受反馈 (takin...

元件服务--Windows的系统零件管理师

今天我想介绍最後一个警告事件,顺便谈谈「元件服务」这回事,他是一个Windows系统管理工具,管理C...

Day 21:在 Hexo 增加作者版权声明(使用 Next 布景)

内容发布到网路上,由於都是开放的,不管是你写的文章、拍摄的相片或是影片,有一定的机率会被转贴。有些人...

Leetcode: 80. Remove Duplicates from Sorted Array II

延续I 变成每种element最多出现2次。   思路 第一直觉是,多加一个判断几次的变数     ...

【Day26】Figma篇 : 从手机预览

Figma可以透过Figma Mirror从手机预览自己的设计且不用透过同一个wifi,马上来实际做...