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

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

什么是Hilt?

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

在Compose项目中配置Hilt

  1. 在项目根build.gradle.kts中添加Hilt插件:
bash 复制代码
plugins {
    ...
    id("com.google.dagger.hilt.android") version "2.51" apply false
}
  1. 在app级别的build.gradle.kts中应用Hilt插件并添加相关依赖:
scss 复制代码
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:
kotlin 复制代码
@HiltAndroidApp
class MyApplication: Application() {
    ...
}

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

在Compose中使用Hilt

  1. 创建接口和实现类

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

kotlin 复制代码
interface GreetingRepository {
    fun getGreeting(): String
}

@Singleton // 标记为单例
class DefaultGreetingRepository @Inject constructor(): GreetingRepository {
    override fun getGreeting() = "Hello Compose + Hilt!"
}
  1. 依赖注入

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

less 复制代码
@AndroidEntryPoint
@Composable
fun GreetingScreen(
    greetingRepository: GreetingRepository = hiltViewModel() // 注入GreetingRepository
) {
    Text(greetingRepository.getGreeting())
}

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

  1. 视图绑定 除了上面提到的ViewModelRepository注入,Hilt也支持给Composable函数提供视图模型。这在处理复杂UI逻辑时非常有用:
kotlin 复制代码
@HiltViewModel
class GreetingViewModel @Inject constructor(
    private val repository: GreetingRepository
) : ViewModel() {
    val greeting: String = repository.getGreeting()
}

@AndroidEntryPoint
@Composable
fun 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 内置了几个关键的组件,如ApplicationComponentActivityRetainedComponent等。开发者无需手动创建这些组件。
  3. 组件层次结构 :Hilt 闱开发者预先设计好了组件的层级结构,并将 Android 类的这些组件绑定。例如 Activity 的一来就被绑定到ActivityComponent
  4. 依赖作用域:Hilt 利用作用域注解确保注入的对象生命周期与宿主组件相同,避免了内存泄露问题。
  5. 优化注入过程 :Hilt 对注入过程做了优化,使其所需编码更少,只需在对应类上添加@AndroidEntryPoint@HiltViewModel注解即可。

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

Hilt之前的依赖注入方案

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

  1. 手动实例化 :最传统的做法就是在需要的地方new出对应的对象实例,这种方式简单但难以维护和单元测试。
  2. 服务定位器(Service Locator) :将对象的创建和获取集中到一个 Locator类中,通过静态方法获取对象。虽然简化了实例化流程,但作用域管理仍然存在问题。
kotlin 复制代码
object ServiceLocator {
    private val greetingRepo = DefaultGreetingRepository()
    
    fun getGreetingRepository(): GreetingRepository {
        return greetingRepo
    }
}

// 使用时:
val repo = ServiceLocator.getGreetingRepository()
  1. 手动 Dagger2:直接使用 Dagger2 框架,需要手写非常多模块化代码,侵入性强,学习成本高。
kotlin 复制代码
// 定义模块
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 库 :例如KoinKodein等,都需要一定的集成成本。

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

kotlin 复制代码
// 定义模块
val appModule = module {
    single<GreetingRepository> { DefaultGreetingRepository() }
}

// 注入 Koin
startKoin {
    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 方案了。

相关推荐
SRC_BLUE_171 小时前
SQLI LABS | Less-39 GET-Stacked Query Injection-Intiger Based
android·网络安全·adb·less
无尽的大道4 小时前
Android打包流程图
android
镭封6 小时前
android studio 配置过程
android·ide·android studio
夜雨星辰4876 小时前
Android Studio 学习——整体框架和概念
android·学习·android studio
邹阿涛涛涛涛涛涛6 小时前
月之暗面招 Android 开发,大家快来投简历呀
android·人工智能·aigc
IAM四十二6 小时前
Jetpack Compose State 你用对了吗?
android·android jetpack·composer
奶茶喵喵叫7 小时前
Android开发中的隐藏控件技巧
android
Winston Wood8 小时前
Android中Activity启动的模式
android
众乐认证8 小时前
Android Auto 不再用于旧手机
android·google·智能手机·android auto
三杯温开水9 小时前
新的服务器Centos7.6 安卓基础的环境配置(新服务器可直接粘贴使用配置)
android·运维·服务器