随着Jetpack Compose正式发布,越来越多的Android开发者开始尝试在项目中使用这个现代化的UI工具箱。与传统的View System相比,Compose提供了声明式UI、无需过度操作View的API等优势。但在实际项目开发中,我们也需要处理依赖注入、异步编程等基础架构的需求。本文将介绍如何在Compose项目中使用Hilt进行依赖注入。
Hilt是Google官方推出的一款基于
Dagger
的依赖注入库,专门面向Android的特性进行了优化。相比
Dagger
,
Hilt
更容易上手和集成,并且对Android类进行了专门绑定,无需手动编写模块。
在Compose项目中配置Hilt
-
在项目根
build.gradle.kts
中添加
Hilt
插件:
plugins {
...
id("com.google.dagger.hilt.android") version "2.51" apply false
}
-
在app级别的
build.gradle.kts
中应用
Hilt
插件并添加相关依赖:
plugins {
id("kotlin-kapt")
id("com.google.dagger.hilt.android")
}
android {
...
}
dependencies {
...
implementation("com.google.dagger:hilt-android:2.51")
kapt("com.google.dagger:hilt-compiler:2.51")
}
-
在Application类中注册
HiltAndroidApp
:
@HiltAndroidApp
class MyApplication: Application() {
...
}
至此,基本配置就完成了。
-
创建接口和实现类
假设我们需要创建一个显示问候语的
Repository
:
interface GreetingRepository {
fun getGreeting(): String
}
@Singleton
class DefaultGreetingRepository @Inject constructor(): GreetingRepository {
override fun getGreeting() = "Hello Compose + Hilt!"
}
-
依赖注入
在Composable函数中,我们可以使用
@AndroidEntryPoint
获取
Hilt
依赖:
@AndroidEntryPoint
@Composable
fun GreetingScreen(
greetingRepository: GreetingRepository = hiltViewModel()
) {
Text(greetingRepository.getGreeting())
}
对于在其他的Android类(如
Activity/Fragment
)中使用依赖的场景,也可以使用
@AndroidEntryPoint
和
@Inject
的方式进行注入,这里不再赘述。
-
视图绑定
除了上面提到的
ViewModel
或
Repository
注入,
Hilt
也支持给
Composable
函数提供视图模型。这在处理复杂UI逻辑时非常有用:
@HiltViewModel
class GreetingViewModel @Inject constructor(
private val repository: GreetingRepository
) : ViewModel() {
val greeting: String = repository.getGreeting()
}
@AndroidEntryPoint
@Composable
fun GreetingScreen(
viewModel: GreetingViewModel = hiltViewModel()
) {
Text(viewModel.greeting)
}
小结
本文简要介绍了在Compose项目中集成Hilt的基本步骤,并演示了如何使用Hilt注入Repository和ViewModel。与传统的手动依赖注入相比,Hilt能够减少很多模板代码,提高开发效率。它与Compose的搭配使用,有助于保持页面代码的干净和可维护性。
下面让我们接着上文来深入探讨一下Hilt的原理,以及在Hilt出现之前Android项目是如何处理依赖注入的,并对比一下Hilt和其他类似依赖注入库的优缺点及使用场景。
Hilt 本质上是一个基于 Dagger2 的封装和扩展。Dagger2是一个功能强大但相对底层的依赖注入框架,需要手动编写大量模块化代码。Hilt 在此基础上做了以下的改进:
-
Android 类自动生成
:Hilt利用了 Dagger2 的编译时注解处理能力,能够自动生成 Android (如
Activity/Fragment
)对应的绑定代码,省去了手动编写模块的步骤。
-
预定义组件
:Hilt 内置了几个关键的组件,如
ApplicationComponent
和
ActivityRetainedComponent
等。开发者无需手动创建这些组件。
-
组件层次结构
:Hilt 闱开发者预先设计好了组件的层级结构,并将 Android 类的这些组件绑定。例如 Activity 的一来就被绑定到
ActivityComponent
。
-
依赖作用域
:Hilt 利用作用域注解确保注入的对象生命周期与宿主组件相同,避免了内存泄露问题。
-
优化注入过程
:Hilt 对注入过程做了优化,使其所需编码更少,只需在对应类上添加
@AndroidEntryPoint
或
@HiltViewModel
注解即可。
总的来说,Hilt 在保留了 Dagger2 强大能力的同时,精简和优化了 Android 平台上的使用体验,让依赖注入变得更易上手。
在 Hilt 出现之前,Android 开发者主要使用以下方式进行依赖注入:
-
手动实例化
:最传统的做法就是在需要的地方
new
出对应的对象实例,这种方式简单但难以维护和单元测试。
-
服务定位器(Service Locator)
:将对象的创建和获取集中到一个
Locator
类中,通过静态方法获取对象。虽然简化了实例化流程,但作用域管理仍然存在问题。
object ServiceLocator {
private val greetingRepo = DefaultGreetingRepository()
fun getGreetingRepository(): GreetingRepository {
return greetingRepo
}
}
val repo = ServiceLocator.getGreetingRepository()
-
手动 Dagger2
:直接使用 Dagger2 框架,需要手写非常多模块化代码,侵入性强,学习成本高。
class GrettingModule {
@Provides
fun provideGreetingRepository(): GreetingRepository {
return DefaultGreetingRepositoryy()
}
}
@Singleton
@Component(modules = [GreetingModule::class])
interface GreetingComponent {
fun getGreetingRepository(): GreetingRepository
}
val component = DaggerGteetingComponent.builder().build()
val repo = component.getGreetingRepository()
-
其他 DI 库
:例如
Koin
、
Kodein
等,都需要一定的集成成本。
这些传统方案各有缺陷,有的存在内存泄露问题,有的编码量大且不易维护等。这就是 Google 决定推出 Hilt 的主要原因。
val appModule = module {
single { DefaultGreetingRepository() }
}
startKoin {
androidContext(this@MyApp)
modules(appModule)
}
val repo: GreetingRepository = get()
除了 Google 自家的 Hilt,还有一些其他依赖注入库也可以在 Android 项目中使用,比如 Koin、Kodein 等。我们来对比一下它们的优缺点:
Hilt
:
Koin
:
Kodein
:
总结
:
-
对于只需要轻量级依赖注入的小型项目,可以考虑 Koin 或 Kodein。
-
对于稳定性和性能有要求的大中型项目,尤其是使用 Jetpack 等官方库的,Hilt 无疑是更好的选择。
-
如果有复杂的自定义需求,仍然可以直接使用 Dagger2。
使用场景分析
不同的依赖注入方案在不同场景下有不同的使用考量:
-
新项目
:如果是全新的项目,建议直接使用 Hilt,它集成简单、使用方便,且有 Google 的长期支持保证。
-
已有项目
:如果项目中已经使用了其他 DI 库,短期内切换到 Hilt 的成本可能较高。除非对稳定性和性能有非常大的需求,否则可以暂时维持现有方案。
-
小型项目
:对于小型 Demo 或简单功能的 App,直接手动
new
对象实例未尝不可,过度使用 DI 反而增加了复杂度和学习成本。
-
大型项目
:大型项目对于可维护性和可测实性的要求更高,合理使用 Hilt 将极大地提升代码质量和架构质量。
-
多平台项目
:如果设计多平台开发,Hilt 主要面向 Android 平台,可以考虑更加通用的方案如手动 Dagger2.
总之,在选择依赖注入解决方案时,需要结合项目的实际需求、开发人员的掌握程度、现有架构等因素进行权衡。切勿为了使用而使用,增加不必要的复杂度。对于大多数 Android 开发人员来说,Hilt 可以说是当下最优雅且易于上手的 DI 方案了。
关注我获取更多知识或者投稿