在 Android 开发的漫漫长路上,你是否曾因 Activity、Fragment 以及各种业务逻辑之间错综复杂的依赖关系而感到头疼?对象之间的紧耦合不仅让代码难以维护,更让单元测试变得举步维艰。依赖注入 正是为解决这一问题而生的设计模式,它的核心思想是将对象的创建和使用分离,从而实现解耦。
提到 Android 平台的依赖注入框架,Dagger 无疑是业界的标杆,以其在编译期生成代码、保证运行时性能的零开销特性著称。然而,不可否认的是,Dagger 的学习曲线极其陡峭,繁琐的配置和大量的样板代码往往让人望而生畏。为了解决这一痛点,Google 推出了 Dagger Hilt。Hilt 建立在 Dagger 之上,专门为 Android 优化,它既保留了 Dagger 的所有强大功能,又通过简化配置和提供预设的生命周期组件,极大地降低了使用门槛。
在本文中,我们将作为一个团队,共同构建一个基于 MVVM 架构的 加密货币列表展示应用。通过实战,你将学会如何利用 Hilt 来管理 ViewModel、Repository 和网络数据的依赖关系,编写出干净、可维护且易于测试的代码。
项目准备与环境配置
在正式开始编码之前,我们需要先搭建好基础项目结构。为了确保你能顺利跟进,我们将使用 Kotlin 作为开发语言,并采用 Gradle 来管理 Hilt 的依赖。这不仅是为了演示,更是目前 Android 开发的最佳实践。
#### Step 1: 项目初始化
首先,打开 Android Studio 创建一个新的项目。为了专注于 Hilt 的核心功能,你可以选择“Empty Activity”模板。请注意,确保在创建向导中勾选或手动配置 Kotlin 支持。关于如何在 Android Studio 中创建项目的具体步骤,相信你已经驾轻就熟,这里我们重点放在后续的配置上。
#### Step 2: 添加 Hilt 依赖
配置 Hilt 是第一步,也是最容易出错的地方。请仔细跟随以下步骤操作。
首先,我们需要在项目级 的 build.gradle (Project: app) 文件中引入 Hilt 的 Gradle 插件路径。这告诉 Gradle 去哪里下载 Hilt 的构建工具。
// 项目级 build.gradle 文件
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
// 添加 Hilt 的 Gradle 插件
classpath ‘com.google.dagger:hilt-android-gradle-plugin:2.38.1‘
}
}
接下来,我们需要在应用级 的 INLINECODE8a2734c3 (Module: app) 文件中应用这个插件,并添加 Hilt 的库依赖。请注意,这里我们使用了 INLINECODE218f6128 (Kotlin Annotation Processing Tool),因为 Hilt 需要在编译期生成代码。
// 应用级 build.gradle 文件
plugins {
id ‘kotlin-android‘
id ‘kotlin-kapt‘
id ‘dagger.hilt.android.plugin‘
}
android {
// 也就是在 defaultConfig 内部可能需要添加
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
// Hilt 核心依赖
implementation ‘com.google.dagger:hilt-android:2.38.1‘
kapt ‘com.google.dagger:hilt-android-compiler:2.38.1‘
// 如果在 ViewModels 或其他 Jetpack 组件中使用 Hilt,通常需要以下依赖
kapt ‘androidx.hilt:hilt-compiler:1.0.0‘
// 其他示例用依赖
implementation ‘com.github.bumptech.glide:glide:4.9.0‘
implementation "androidx.activity:activity-ktx:1.4.0"
}
> 💡 实用见解: 你可能会遇到编译速度变慢的情况。为了优化性能,你可以尝试在 INLINECODE18ce98b9 中添加 INLINECODEfa014ac7 来调整注解处理器的行为,或者确保你的 Gradle Daemon 拥有足够的内存。
最后,别忘了点击 Sync Now。如果同步成功,说明 Hilt 已经成功入驻你的项目。
在开始编写代码之前,为了让我们的应用看起来更专业,让我们先美化一下 UI。转到 app/res/values/colors.xml,添加以下主题色,这样我们的界面看起来会更加清爽现代。
#0F9D58
#16E37F
#03DAC5
#FFFFFF
核心代码编写:构建 Hilt 架构
现在,让我们进入最激动人心的部分:编写代码。我们将按照从底层到上层的顺序,逐步构建应用。
#### Step 3: 初始化 Hilt
Hilt 需要知道应用程序的入口点。在 Android 中,我们需要自定义一个 Application 类,并使用 @HiltAndroidApp 注解。这个注解会触发 Hilt 的代码生成器,为你的应用程序创建一个依赖容器,也就是我们常说的“根组件”。
创建一个名为 INLINECODE52f409af 的文件,并继承自 INLINECODE81cd1ae1:
package com.example.cryptocurrencyapp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
/**
* @HiltAndroidApp 注解将触发 Hilt 代码生成,
* 使其包含一个应用级别的依赖容器。
*/
@HiltAndroidApp
class HiltApplication : Application() {
// 在这里可以做一些全局初始化操作,比如日志工具初始化
}
关键步骤: 创建了类还不够,我们还需要在 AndroidManifest.xml 中注册它,并且加上互联网权限(因为稍后我们可能会涉及到加载网络图片或数据,虽然本例使用模拟数据,但这是一个好习惯)。
> ⚠️ 常见错误: 如果你在运行应用时遇到崩溃,请首先检查 INLINECODEb987a636 属性是否填写正确,是否指向了你刚刚创建的 INLINECODE48e8d754 类。这是一个非常容易忽略的细节。
#### Step 4: 定义数据模型与抽象层
让我们来看看如何利用 Hilt 注入具体的实现。首先,我们需要一个数据模型来表示加密货币。
创建数据类 Cryptocurrency:
// Cryptocurrency.kt
/**
* 数据模型:表示一种加密货币
*/
data class Cryptocurrency(
val image: String, // 图片 URL
val name: String // 名称
)
为了符合 Clean Architecture 和 MVVM 的最佳实践,我们不应该让 ViewModel 直接依赖具体的实现细节。相反,我们应该依赖抽象。让我们定义一个接口 CryptocurrencyRepository,然后创建它的一个实现。
首先创建接口:
// CryptocurrencyRepository.kt
interface CryptocurrencyRepository {
fun getCryptoCurrency(): List
}
然后,我们需要一个具体的实现类来提供数据。为了演示依赖注入的强大之处,我们暂时在内部提供一些模拟数据。在实际生产环境中,你可能会在这里注入 Retrofit 或 Room 数据库,ViewModel 代码甚至不需要修改!
创建实现类 CryptocurrencyRepositoryImpl:
// CryptocurrencyRepositoryImpl.kt
import javax.inject.Inject
import javax.inject.Singleton
/**
* 使用 @Singleton 注解告诉 Hilt,
* 这个 Repository 在整个应用生命周期中应该只有一个实例。
* 使用 @Inject 注解告诉 Hilt 如何创建这个类的实例。
*/
@Singleton
class CryptocurrencyRepositoryImpl @Inject constructor() : CryptocurrencyRepository {
override fun getCryptoCurrency(): List {
// 模拟数据源
return listOf(
Cryptocurrency("https://bitcoindotorg.github.io/img/icons/android-icon-192x192.png", "Bitcoin"),
Cryptocurrency("https://ethereum.org/favicon.ico", "Ethereum"),
Cryptocurrency("https://raw.githubusercontent.com/bitcoin/bitcoin/master/src/qt/res/src/bitcoin.svg", "Litecoin")
)
}
}
请注意这里的 INLINECODE3751d241。这是 Hilt 的核心指令。它告诉 Hilt:“嘿,如果你需要一个 INLINECODE3c9fb2c7 的实例,那就调用这个构造函数来创建它。”
#### Step 5: 编写 ViewModel 并注入依赖
现在,让我们看看如何在 ViewModel 中使用 Repository。在 MVVM 架构中,ViewModel 负责持有 UI 数据,并通常需要从 Repository 获取数据。在以前,你需要自己 new Repository(),但在 Hilt 中,你只需要请求它。
创建 CryptoViewModel.kt:
// CryptoViewModel.kt
import androidx.lifecycle.ViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
/**
* @HiltViewModel 注解告诉 Hilt 这是一个 ViewModel,
* 需要由 Hilt 来管理和提供。
* 构造函数中的 repo 参数会自动由 Hilt 传入,
* 即使是构造函数注入也不需要 Factory 适配器了!
*/
@HiltViewModel
class CryptoViewModel @Inject constructor(
private val repository: CryptocurrencyRepository
) : ViewModel() {
// 私有的 MutableLiveData,用于内部更新数据
private val _cryptoList = MutableLiveData<List>()
// 公开的 LiveData,供 UI 层观察
val cryptoList: LiveData<List> = _cryptoList
init {
// 初始化时加载数据
loadData()
}
private fun loadData() {
// 直接调用 Repository 的方法,无需关心它是如何创建的
val data = repository.getCryptoCurrency()
_cryptoList.postValue(data)
}
}
深入讲解: 看到了吗?在 INLINECODE6a405fbd 的构造函数中,我们传入了 INLINECODEee62bde1。我们不需要手动写 INLINECODEe26f90a3。Hilt 检查到了 ViewModel 需要 INLINECODE8fa5ed3a,于是它去寻找提供了这个接口的实现(即我们刚刚写的 CryptocurrencyRepositoryImpl),并自动实例化它。这就是依赖注入的魔法——依赖由框架“注入”到了类中。
#### Step 6: 使用 @AndroidEntryPoint 注解 UI 层
现在我们需要一个 Activity 来展示数据。要在 Activity 中获取 ViewModel,我们必须让 Hilt 知道这个 Activity 也属于它的管理范围。
创建或修改 MainActivity.kt:
// MainActivity.kt
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
/**
* @AndroidEntryPoint 注解告诉 Hilt,
* 这个 Activity 可以接收依赖注入的成员(如 ViewModel)。
*/
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
// 注意:这里不需要使用lateinit var viewModel: CryptoViewModel = ... 旧的方式了
// Hilt 扩展插件允许我们通过 viewModels() 委托直接获取 Hilt 管理的 ViewModel
// private val viewModel: CryptoViewModel by viewModels()
// 为了兼容性,演示最基础的获取方式:实际上你应该使用 Jetpack 扩展库提供的 by viewModels()
// 这里的代码假设你已经导入了 androidx.fragment.app.viewModels 或 activity-ktx
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// 初始化 RecyclerView 和 Adapter 代码省略...
// 重点在于观察 LiveData
}
}
> 🚀 性能优化建议: 在实际开发中,请使用 private val viewModel: CryptoViewModel by viewModels() 来获取 ViewModel,这是 Android KTX 提供的属性委托,能极大简化代码。
总结与后续步骤
通过构建这个简单的加密货币应用,我们一起探索了 Dagger Hilt 的核心工作流程:
- Application 设置: 使用
@HiltAndroidApp启动整个依赖图谱。 - 提供依赖: 使用
@Inject constructor告诉 Hilt 如何创建对象(如 Repository)。 - 注入依赖: 在 ViewModel 的构造函数中直接请求依赖,并配合
@HiltViewModel。 - 连接 UI: 在 Activity 中使用
@AndroidEntryPoint来启用注入功能。
下一步你可以做什么?
我们的旅程还没有结束。在下一阶段,你可以尝试挑战以下任务来巩固知识:
- 添加模块与接口绑定: 当你无法修改源码(比如第三方库)时,你需要学习如何创建 INLINECODE32b81554 和 INLINECODE38f88650。
- 替换数据源: 尝试引入 Retrofit 和 Coroutines,将模拟数据的 Repository 替换为真实的网络请求。你会发现,由于我们使用了接口,ViewModel 层的代码几乎不需要改动!
掌握 Hilt 是迈向专业 Android 开发者的重要一步,它不仅能让你写出更简洁的代码,还能让项目的架构更加清晰、健壮。希望这篇文章对你有所帮助,祝你编码愉快!