专栏名称: Android技术之家
主要分享Android相关技术文章、移动互联网的相关产品和资讯。关注你将学习到更多基础以及框架相关的知识,为您的工作助力!
目录
相关文章推荐
51好读  ›  专栏  ›  Android技术之家

升级Android项目,就用Hilt!全面解锁依赖注入的高效之道

Android技术之家  · 公众号  ·  · 2024-06-17 07:56

正文

请到「今天看啥」查看全文


随着Jetpack Compose正式发布,越来越多的Android开发者开始尝试在项目中使用这个现代化的UI工具箱。与传统的View System相比,Compose提供了声明式UI、无需过度操作View的API等优势。但在实际项目开发中,我们也需要处理依赖注入、异步编程等基础架构的需求。本文将介绍如何在Compose项目中使用Hilt进行依赖注入。

什么是Hilt?

Hilt是Google官方推出的一款基于 Dagger 的依赖注入库,专门面向Android的特性进行了优化。相比 Dagger Hilt 更容易上手和集成,并且对Android类进行了专门绑定,无需手动编写模块。

在Compose项目中配置Hilt

  1. 在项目根 build.gradle.kts 中添加 Hilt 插件:

plugins {    ...    id("com.google.dagger.hilt.android") version "2.51" apply false}

  1. 在app级别的 build.gradle.kts 中应用 Hilt 插件并添加相关依赖:

plugins {    id("kotlin-kapt")    id("com.google.dagger.hilt.android")}
android { ...}
dependencies { ... // Dagger - Hilt implementation("com.google.dagger:hilt-android:2.51") kapt("com.google.dagger:hilt-compiler:2.51")}

  1. 在Application类中注册 HiltAndroidApp :

@HiltAndroidAppclass MyApplication: Application() {    ...}

至此,基本配置就完成了。

在Compose中使用Hilt

  1. 创建接口和实现类

假设我们需要创建一个显示问候语的 Repository :

interface GreetingRepository {    fun getGreeting(): String}
@Singleton // 标记为单例class DefaultGreetingRepository @Inject constructor(): GreetingRepository { override fun getGreeting() = "Hello Compose + Hilt!"}

  1. 依赖注入

在Composable函数中,我们可以使用 @AndroidEntryPoint 获取 Hilt 依赖:

@AndroidEntryPoint@Composablefun GreetingScreen(    greetingRepository: GreetingRepository = hiltViewModel() // 注入GreetingRepository) {    Text(greetingRepository.getGreeting())}


对于在其他的Android类(如 Activity/Fragment )中使用依赖的场景,也可以使用 @AndroidEntryPoint @Inject 的方式进行注入,这里不再赘述。

  1. 视图绑定 除了上面提到的 ViewModel Repository 注入, Hilt 也支持给 Composable 函数提供视图模型。这在处理复杂UI逻辑时非常有用:

@HiltViewModelclass GreetingViewModel @Inject constructor(    private val repository: GreetingRepository) : ViewModel() {    val greeting: String = repository.getGreeting()}
@AndroidEntryPoint@Composablefun GreetingScreen( viewModel: GreetingViewModel = hiltViewModel() // 注册ViewModel) { Text(viewModel.greeting)}

小结

本文简要介绍了在Compose项目中集成Hilt的基本步骤,并演示了如何使用Hilt注入Repository和ViewModel。与传统的手动依赖注入相比,Hilt能够减少很多模板代码,提高开发效率。它与Compose的搭配使用,有助于保持页面代码的干净和可维护性。

下面让我们接着上文来深入探讨一下Hilt的原理,以及在Hilt出现之前Android项目是如何处理依赖注入的,并对比一下Hilt和其他类似依赖注入库的优缺点及使用场景。

Hilt的实现原理

Hilt 本质上是一个基于 Dagger2 的封装和扩展。Dagger2是一个功能强大但相对底层的依赖注入框架,需要手动编写大量模块化代码。Hilt 在此基础上做了以下的改进:

  1. Android 类自动生成 :Hilt利用了 Dagger2 的编译时注解处理能力,能够自动生成 Android (如 Activity/Fragment )对应的绑定代码,省去了手动编写模块的步骤。

  2. 预定义组件 :Hilt 内置了几个关键的组件,如 ApplicationComponent ActivityRetainedComponent 等。开发者无需手动创建这些组件。

  3. 组件层次结构 :Hilt 闱开发者预先设计好了组件的层级结构,并将 Android 类的这些组件绑定。例如 Activity 的一来就被绑定到 ActivityComponent

  4. 依赖作用域 :Hilt 利用作用域注解确保注入的对象生命周期与宿主组件相同,避免了内存泄露问题。

  5. 优化注入过程 :Hilt 对注入过程做了优化,使其所需编码更少,只需在对应类上添加 @AndroidEntryPoint @HiltViewModel 注解即可。

总的来说,Hilt 在保留了 Dagger2 强大能力的同时,精简和优化了 Android 平台上的使用体验,让依赖注入变得更易上手。

Hilt之前的依赖注入方案

在 Hilt 出现之前,Android 开发者主要使用以下方式进行依赖注入:

  1. 手动实例化 :最传统的做法就是在需要的地方 new 出对应的对象实例,这种方式简单但难以维护和单元测试。

  2. 服务定位器(Service Locator) :将对象的创建和获取集中到一个 Locator 类中,通过静态方法获取对象。虽然简化了实例化流程,但作用域管理仍然存在问题。

object ServiceLocator {    private val greetingRepo = DefaultGreetingRepository()        fun getGreetingRepository(): GreetingRepository {        return greetingRepo    }}
// 使用时:val repo = ServiceLocator.getGreetingRepository()

  1. 手动 Dagger2 :直接使用 Dagger2 框架,需要手写非常多模块化代码,侵入性强,学习成本高。

// 定义模块class GrettingModule {    @Provides    fun provideGreetingRepository(): GreetingRepository {        return DefaultGreetingRepositoryy()    }}
// 定义 Component@Singleton@Component(modules = [GreetingModule::class])interface GreetingComponent { fun getGreetingRepository(): GreetingRepository}
// 使用时需要先获取 Component 实例val component = DaggerGteetingComponent.builder().build()val repo = component.getGreetingRepository()

  1. 其他 DI 库 :例如 Koin Kodein 等,都需要一定的集成成本。

这些传统方案各有缺陷,有的存在内存泄露问题,有的编码量大且不易维护等。这就是 Google 决定推出 Hilt 的主要原因。

// 定义模块val appModule = module {    single { DefaultGreetingRepository() }}
// 注入 KoinstartKoin { androidContext(this@MyApp) modules(appModule)}
// 使用时通过 get()获取val repo: GreetingRepository = get()

Hilt 与其他 DI 库的比较

除了 Google 自家的 Hilt,还有一些其他依赖注入库也可以在 Android 项目中使用,比如 Koin、Kodein 等。我们来对比一下它们的优缺点:

Hilt

  • 优点:继承简单、完全基于 Dagger2提供可靠性保证、与 Jetpack 高度集成、内存安全。

  • 缺点:不太灵活,必须遵循 Hilt 的规范,如果想要自定义相对比较困难。

Koin

  • 优点:使用 Kotlin DSL 非常轻量简洁,对 Java 项目也有支持。

  • 缺点:功能没有 Hilt 全面,不支持注解绑定,可能存在内存泄露风险。

Kodein

  • 优点:轻量级,零渗透设计,易于集成和使用。

  • 缺点:相比 Koin 功能偏少,项目维护不太活跃,对大型项目支持较弱。

总结

  • 对于只需要轻量级依赖注入的小型项目,可以考虑 Koin 或 Kodein。

  • 对于稳定性和性能有要求的大中型项目,尤其是使用 Jetpack 等官方库的,Hilt 无疑是更好的选择。

  • 如果有复杂的自定义需求,仍然可以直接使用 Dagger2。

使用场景分析

不同的依赖注入方案在不同场景下有不同的使用考量:

  • 新项目 :如果是全新的项目,建议直接使用 Hilt,它集成简单、使用方便,且有 Google 的长期支持保证。

  • 已有项目 :如果项目中已经使用了其他 DI 库,短期内切换到 Hilt 的成本可能较高。除非对稳定性和性能有非常大的需求,否则可以暂时维持现有方案。

  • 小型项目 :对于小型 Demo 或简单功能的 App,直接手动 new 对象实例未尝不可,过度使用 DI 反而增加了复杂度和学习成本。

  • 大型项目 :大型项目对于可维护性和可测实性的要求更高,合理使用 Hilt 将极大地提升代码质量和架构质量。

  • 多平台项目 :如果设计多平台开发,Hilt 主要面向 Android 平台,可以考虑更加通用的方案如手动 Dagger2.

总之,在选择依赖注入解决方案时,需要结合项目的实际需求、开发人员的掌握程度、现有架构等因素进行权衡。切勿为了使用而使用,增加不必要的复杂度。对于大多数 Android 开发人员来说,Hilt 可以说是当下最优雅且易于上手的 DI 方案了。

作者:谋爱先谋生爱人先爱己链接:https://juejin.cn/post/7348464590159609908

关注我获取更多知识或者投稿







请到「今天看啥」查看全文