从 Dagger 迁移到 Hilt 可带来的收益
Hilt 发布于 2020 年 6 月,为 Android 提供了依赖项注入 (DI) 的标准化方案。对于新项目,Hilt 有着编译期校验,良好的运行时性能以及扩展性 (阅读文章 Android 和 Hilt 中限定作用域,获取更多信息)。然而,Hilt 对于已经使用 Dagger 的应用有何优势呢?您是否应该将现有的应用迁移到 Hilt 呢?以下几点阐述了您的团队需要投入精力到迁移工作中的原因。
✅ 支持 AndroidX 扩展
如果您已经使用 Dagger 处理 ViewModel 或者 WorkManager,您就会知道,注入您自己的 ViewModelFactory 与 WorkerFactory 需要大量的模板代码,并且需要 Dagger 相关知识。最常见的实现就是使用多绑定,这是 Dagger 中最复杂的功能之一,开发人员往往难以理解。Hilt 通过移除模板代码大大简化了 AndroidX 的使用。更妙的是,您甚至无需对 Android Framework 的类注入 Factory,就好像没有使用 Hilt 一样。通过使用 @HiltViewModel,Hilt 为您创建了正确的 ViewModelProvider.Factory,正因如此,被 @AndroidEntryPoint 注解的 Activity 和 Fragment 可以直接使用。
多绑定
https://dagger.dev/dev-guide/multibindings.html
@HiltViewModel
class PlayViewModel @Inject constructor(
val db: MusicDatabase,
) : ViewModel() { ... }
@AndroidEntryPoint
class PlayActivity : AppCompatActivity() {
val viewModel: PlayViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle) {
super.onCreate(bundle)
viewModel.play()
}
}
✅ 支持测试 API
DI (依赖项注入) 本应该使测试更加容易,但讽刺的是,使用 Dagger 进行测试需要大量的工作。实际上,您必须同时维护正式和测试的 Dagger 关系图,而 Hilt 的实现方式则更加便捷。
大量的工作
https://developer.android.google.cn/training/dependency-injection/dagger-android#dagger-testingHilt 的实现方式
https://developer.android.google.cn/training/dependency-injection/hilt-testing
Hilt 测试可以使用 @UninstallModules 功能显式修改 DI 关系图。除此之外,还提供了诸如 @BindValue 一类的其他功能,可以轻松地将测试字段绑定到 DI 关系图中。
@UninstallModules
https://developer.android.google.cn/training/dependency-injection/hilt-testing#replace-binding@BindValue
https://developer.android.google.cn/training/dependency-injection/hilt-testing#binding-new
@UninstallModules(AnalyticsModule::class)
@HiltAndroidTest
class ExampleTest {
@get:Rule
var hiltRule = HiltAndroidRule(this)
@BindValue @JvmField
val analyticsRepository = FakeAnalyticsRepository()
@Test
fun myTest() { ... }
}
✅ 良好的一致性
在 Dagger 中有很多种方法可以实现相同的功能。由于早期缺乏 Android 应用的指南文档 (去年我们已经解决了这一问题,例如指南文章: Dagger 基础知识),导致社区中出现许多争论,最终造成了不同开发者在 Android 应用中使用和配置 Dagger 的方式不一致。
Dagger 基础知识
https://developer.android.google.cn/training/dependency-injection/dagger-basics
您可能会存在异议,认为迁移到 Hilt 是不值得的,因为当前的 Dagger 配置已经非常完善,并且您完全掌握 Dagger 的工作原理以及所有依赖项是如何被注入的。这对您个人来说可能是正确的,但是您是否考虑过团队的其他成员 (包括潜在的未来同事)?您是否能确保切换至新项目时仍能正常运作?了解 Dagger 在应用中的配置和使用是一项艰巨且耗时的工作。
通过在应用中使用 Hilt,上述工作量将会显著减少,因为所有 Hilt 应用都使用相同的配置。新加入团队的开发者不会对 Hilt 的配置感到困惑,因为这和他们之前的配置方式几乎相同。
✅ 支持自定义组件
https://medium.com/androiddevelopers/hilt-adding-components-to-the-hierarchy-96f207d6d92d
虽然自定义组件降低了一致性,但是这会给您带来很大收益!自定义组件也可以配合模块自动发现功能 (@InstallIn 注解功能) 以及测试替换功能一起使用。
@InstallIn
https://developer.android.google.cn/training/dependency-injection/hilt-android#hilt-modules
但是,自定义组件和 Hilt 内置组件的区别在于,这些组件无法自动注入到 Android Framework 的类中 (即 @AndroidEntryPoint 的功能)。
✅ 支持 Dagger 和 Hilt 交互
Hilt 和 Dagger 可以共存!如果允许 Hilt 接管 SingletonComponent,则可以在应用中某些部分使用 Hilt 的特性,并从中受益,而其他特殊部分仍保留 Dagger。这同样意味着可以逐步完成向 Hilt 的迁移:
❌ 不支持组件依赖
Hilt 的易用意味着它代替您做出了一些决定。Hilt 在组件关系中采用了子组件模式,您可以查看相关文档了解这样设计的原因。如果您坚信您的应用更适合采用组件依赖,那么 Hilt 就不是您应用的正确选择。
相关文档
https://dagger.dev/hilt/subcomponents-vs-deps
详细的迁移文档 https://dagger.dev/hilt/migration-guide Codelab | 从 Dagger 迁移到 Hilt https://developer.android.google.cn/codelabs/android-dagger-to-hilt Google I/O 应用迁移到 Hilt 的博客和代码提交记录 文章 https://medium.com/androiddevelopers/migrating-the-google-i-o-app-to-hilt-f3edf03affe5 代码提交记录 https://github.com/google/iosched/commit/9c20fdd52d446e5fdb03369e50fb196c31ae16e3
Hilt 和 AssistedInject 协同使用要点 https://gist.github.com/manuelvicnt/437668cda3a891d347e134b1de29aee1
如果您有任何问题,或者您需要更多相关信息,请在文章下留言反馈。
推荐阅读