从 Dagger 迁移到 Hilt 可带来的收益

1,195 阅读4分钟

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 可以直接使用。

@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 的实现方式 则更加便捷。

Hilt 测试可以使用 @UninstallModules 功能显式修改 DI 关系图。除此之外,还提供了诸如 @BindValue 一类的其他功能,可以轻松地将测试字段绑定到 DI 关系图中。

@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 的方式不一致。

您可能会存在异议,认为迁移到 Hilt 是不值得的,因为当前的 Dagger 配置已经非常完善,并且您完全掌握 Dagger 的工作原理以及所有依赖项是如何被注入的。这对您个人来说可能是正确的,但是您是否考虑过团队的其他成员 (包括潜在的未来同事)?您是否能确保切换至新项目时仍能正常运作?了解 Dagger 在应用中的配置和使用是一项艰巨且耗时的工作。

通过在应用中使用 Hilt,上述工作量将会显著减少,因为所有 Hilt 应用都使用相同的配置。新加入团队的开发者不会对 Hilt 的配置感到困惑,因为这和他们之前的配置方式几乎相同。

✅ 支持自定义组件

除了已经定义的标准组件之外,Hilt 也提供了创建自定义组件并添加到组件层次结构中的方法,详见文章 Hilt — 添加组件到层次结构

虽然自定义组件降低了一致性,但是这会给您带来很大收益!自定义组件也可以配合模块自动发现功能 (@InstallIn 注解功能) 以及测试替换功能一起使用。

但是,自定义组件和 Hilt 内置组件的区别在于,这些组件无法自动注入到 Android Framework 的类中 (即 @AndroidEntryPoint 的功能)。

✅ 支持 Dagger 和 Hilt 交互

Hilt 和 Dagger 可以共存!如果允许 Hilt 接管 SingletonComponent,则可以在应用中某些部分使用 Hilt 的特性,并从中受益,而其他特殊部分仍保留 Dagger。这同样意味着可以 逐步完成向 Hilt 的迁移

❌ 不支持组件依赖

Hilt 的易用意味着它代替您做出了一些决定。Hilt 在组件关系中采用了子组件模式,您可以查看 相关文档 了解这样设计的原因。如果您坚信您的应用更适合采用组件依赖,那么 Hilt 就不是您应用的正确选择。

在大多数项目中,将 Dagger 迁移到 Hilt 是值得的。Hilt 给您带来的收益超出了更新所需付出的努力。我们提供了很多资源来助力迁移,请参阅:

如果您有任何问题,或者您需要更多相关信息,请在文章下方留言反馈。