Hilt依赖注入从手动new到自动装配的完整实现方法
在写代码时,一个类经常需要用到其他类。比如 ArticleViewModel 需要 ArticleRepository,ArticleRepository 又需要 ArticleDao 和 ApiService。

最直接的写法是什么?在构造函数里自己创建。
class ArticleViewModel {private val repository = ArticleRepository(ArticleDao(database),ApiService.create())}
这种做法问题不少:耦合度高,ViewModel 得知道怎么创建各种底层对象,换实现就得改它;难以测试,单元测试想传个假的数据库或 Mock 接口进去,发现根本做不到;对象复用困难,多个地方都需要 ApiService,各自创建出来的就不是同一个实例。
依赖注入的思路其实很简单:让类别再自己创建依赖对象,而是从外部传进来。
class ArticleViewModel(private val repository: ArticleRepository) {// 直接用 repository,不关心它怎么来的}
但真要是手写依赖注入,在 Application 或 Activity 里手动层层构造对象,代码量会快速膨胀。这正是依赖注入框架存在的意义——帮你自动完成对象的创建和传递。
为什么选 Hilt
Android 上常见的 DI 方案有 Dagger、Koin 和 Hilt。Dagger 功能强大但配置复杂,学习曲线陡峭;Koin 基于 Kotlin DSL,写法简洁,不过运行时解析,编译期不检查;而 Hilt 是 Google 在 Dagger 基础上封装的 Android 专用方案,保留了编译期类型检查,同时大幅简化了配置。
Hilt 的核心优势很明确:它具备 Android 感知,自动为 Application、Activity、Fragment、Service、ViewModel 提供注入支持;编译期就能验证依赖是否缺失或类型不匹配,不会等到运行时崩溃;所有组件使用相同的注解体系,团队协作成本低;而且 Google 官方推荐,Jetpack 组件逐步都在提供 Hilt 集成。
接入 Hilt
添加依赖
在项目根 build.gradle 中:
plugins { id 'com.google.dagger.hilt.android' version '2.51' apply false}
在 app 模块 build.gradle 中:
plugins { id 'com.android.application'id 'kotlin-kapt'id 'com.google.dagger.hilt.android'}dependencies { implementation "com.google.dagger:hilt-android:2.51"kapt "com.google.dagger:hilt-android-compiler:2.51"}
如果项目使用 KSP 替代 kapt:
plugins { id 'com.google.devtools.ksp'id 'com.google.dagger.hilt.android'}dependencies { implementation "com.google.dagger:hilt-android:2.51"ksp "com.google.dagger:hilt-android-compiler:2.51"}
Application 入口
Hilt 需要一个继承自 Application 的类,并标注 @HiltAndroidApp:
@HiltAndroidAppclass MyApplication : Application()
别忘了在 AndroidManifest.xml 中声明:
@HiltAndroidApp 会触发 Hilt 的代码生成,创建一个应用级别的依赖容器,这是整个 Hilt 配置里唯一需要手动改 Application 的地方。
@AndroidEntryPoint:让 Android 组件支持注入
Activity、Fragment、Service、BroadcastReceiver 需要用 @AndroidEntryPoint 标记后才能使用注入:
@AndroidEntryPointclass ArticleActivity : AppCompatActivity() {@Injectlateinit var repository: ArticleRepositoryoverride fun onCreate(sa vedInstanceState: Bundle?) {super.onCreate(sa vedInstanceState)// repository 已经可以使用了}}
Fragment 也一样:
@AndroidEntryPointclass ArticleFragment : Fragment() {@Injectlateinit var repository: ArticleRepository}
@AndroidEntryPoint 的含义很直接——这个 Android 组件需要 Hilt 提供依赖。Hilt 会在合适的生命周期回调中完成注入。
有一个容易踩的坑:如果 Fragment 的宿主 Activity 没有标 @AndroidEntryPoint,Fragment 的注入会报错。Hilt 的依赖关系是沿着组件层级向上传递的。
@Inject:标记构造函数注入
对于普通的 Kotlin 类,用 @Inject 标记构造函数即可让 Hilt 知道如何创建它:
class ArticleRepository @Inject constructor(private val apiService: ApiService,private val articleDao: ArticleDao) {suspend fun getArticles(): List
当 Hilt 需要创建 ArticleRepository 时,它会自动去找 ApiService 和 ArticleDao 的创建方式,层层解析,直到所有依赖都满足。如果某个依赖找不到,编译时就会报错,而不是等到运行时崩溃。这是 Hilt 基于 Dagger 最实用的特性之一。
@Module 和 @Provides:告诉 Hilt 如何创建特殊对象
不是所有类都能用 @Inject constructor 标记。比如第三方库的类、接口实现、需要复杂初始化逻辑的对象,这时候就需要用 Module 来提供。
@Module@InstallIn(SingletonComponent::class)object NetworkModule {@Provides@Singletonfun provideOkHttpClient(): OkHttpClient {return OkHttpClient.Builder().connectTimeout(30, TimeUnit.SECONDS).addInterceptor(HttpLoggingInterceptor().apply {level = HttpLoggingInterceptor.Level.BODY}).build()}@Provides@Singletonfun provideRetrofit(client: OkHttpClient): Retrofit {return Retrofit.Builder().baseUrl("https://api.example.com/").client(client).addConverterFactory(GsonConverterFactory.create()).build()}@Provides@Singletonfun provideApiService(retrofit: Retrofit): ApiService {return retrofit.create(ApiService::class.ja va)}}
几个关键点:@Module 表示这是一个提供依赖的模块;@InstallIn(SingletonComponent::class) 表示这个 Module 安装在全局单例容器中,整个应用共享;@Provides 标注的方法就是创建对象的方式;@Singleton 表示全局只创建一次,所有注入的地方共享同一个实例。
方法的参数就是依赖。Hilt 会自动解析:provideRetrofit 需要 OkHttpClient,Hilt 会先调用 provideOkHttpClient(),拿到结果后传给 provideRetrofit()。
@Binds:接口绑定的简洁写法
如果接口只有一个实现,可以用 @Binds 代替 @Provides,代码更简洁:
@Module@InstallIn(SingletonComponent::class)abstract class RepositoryModule {@Bindsabstract fun bindArticleRepository(impl: ArticleRepositoryImpl): ArticleRepository}
@Binds 只能用在抽象类和抽象方法上。它告诉 Hilt:当需要 ArticleRepository 接口时,提供 ArticleRepositoryImpl 实现。使用 @Binds 的前提是实现类的构造函数标了 @Inject。
class ArticleRepositoryImpl @Inject constructor(private val api: ApiService,private val dao: ArticleDao) : ArticleRepository {// ...}
Room 数据库的 Module 写法
Room 的 Database 和 DAO 通常也用 Module 提供:
@Module@InstallIn(SingletonComponent::class)object DatabaseModule {@Provides@Singletonfun provideDatabase(@ApplicationContext context: Context): AppDatabase {return Room.databaseBuilder(context,AppDatabase::class.ja va,"app.db").build()}@Providesfun provideArticleDao(database: AppDatabase): ArticleDao {return database.articleDao()}}
@ApplicationContext 是 Hilt 内置的 Qualifier,用来注入 Application 的 Context。如果需要 Activity 的 Context,用 @ActivityContext。这样配置后,任何类的构造函数里只要写 private val dao: ArticleDao,Hilt 就会自动创建并注入。
Hilt 与 ViewModel
ViewModel 的注入方式稍有不同。不能直接用 @Inject constructor 配合 @AndroidEntryPoint,而是要用 @HiltViewModel:
@HiltViewModelclass ArticleViewModel @Inject constructor(private val repository: ArticleRepository) : ViewModel() {private val _uiState = MutableStateFlow(ArticleUiState())val uiState: StateFlow
在 Activity 或 Fragment 中获取 ViewModel 时,不需要任何额外配置:
@AndroidEntryPointclass ArticleActivity : AppCompatActivity() {private val viewModel: ArticleViewModel by viewModels()override fun onCreate(sa vedInstanceState: Bundle?) {super.onCreate(sa vedInstanceState)viewModel.loadArticles()}}
Compose 中使用也很自然:
@Composablefun ArticleScreen(viewModel: ArticleViewModel = hiltViewModel()) {val uiState by viewModel.uiState.collectAsStateWithLifecycle()// 根据 uiState 渲染 UI}
hiltViewModel() 来自 androidx.hilt:hilt-na vigation-compose,需要额外添加依赖:
implementation "androidx.hilt:hilt-na vigation-compose:1.2.0"
作用域:控制对象的生命周期
Hilt 中不同的组件有不同的作用域:
| 作用域 | 组件 | 生命周期 |
|---|---|---|
@Singleton | SingletonComponent | 整个应用 |
@ActivityScoped | ActivityComponent | Activity 存活期间 |
@FragmentScoped | FragmentComponent | Fragment 存活期间 |
@ViewModelScoped | ViewModelComponent | ViewModel 存活期间 |
@ServiceScoped | ServiceComponent | Service 存活期间 |
一般规则:网络层、数据库、Repository 用 @Singleton,全局共享;ViewModel 用 @HiltViewModel,内部依赖默认跟随 ViewModel 生命周期;只有确实需要和 Activity 或 Fragment 生命周期绑定的对象,才使用对应作用域。
必须警惕的是:不要在 SingletonComponent 的 Module 中注入 Activity Context。全局单例的寿命远超 Activity,持有 Activity Context 会导致内存泄漏。
@Qualifier:区分同类型依赖
有时接口有多个实现,Hilt 不知道该注入哪一个。比如项目中有正式环境和测试环境两套 ApiService:
@Qualifier@Retention(AnnotationRetention.BINARY)annotation class ProdApi@Qualifier@Retention(AnnotationRetention.BINARY)annotation class TestApi
在 Module 中标注:
@Module@InstallIn(SingletonComponent::class)object NetworkModule {@Provides@Singleton@ProdApifun provideProdApi(retrofit: Retrofit): ApiService {return retrofit.create(ProdApiService::class.ja va)}@Provides@Singleton@TestApifun provideTestApi(retrofit: Retrofit): ApiService {return retrofit.create(TestApiService::class.ja va)}}
注入时指定要哪个:
class DataRepository @Inject constructor(@ProdApi private val apiService: ApiService)
Hilt 内置了两个常用 Qualifier:@ApplicationContext 和 @ActivityContext,不需要自己定义。
实战:一个完整的 Hilt 项目结构
整理一下典型项目中 Hilt 的目录组织:
com.example.app/├── MyApplication.kt// @HiltAndroidApp├── di/│ ├── NetworkModule.kt// OkHttpClient, Retrofit, ApiService│ ├── DatabaseModule.kt // Room Database, DAO│ └── RepositoryModule.kt // @Binds 接口绑定├── data/│ ├── remote/│ │ └── ApiService.kt│ ├── local/│ │ ├── AppDatabase.kt│ │ └── ArticleDao.kt│ └── repository/│ ├── ArticleRepository.kt // 接口│ └── ArticleRepositoryImpl.kt // @Inject constructor├── ui/│ ├── ArticleActivity.kt// @AndroidEntryPoint│ └── ArticleViewModel.kt // @HiltViewModel
每个文件只做一件事,依赖关系很清晰:NetworkModule 提供 ApiService,DatabaseModule 提供 ArticleDao,RepositoryModule 把 ArticleRepositoryImpl 绑定到 ArticleRepository 接口,ArticleViewModel 构造函数注入 ArticleRepository,ArticleActivity 通过 by viewModels() 拿到 ViewModel。整个过程没有任何手动 new 或工厂方法,Hilt 在编译期生成了所有必要的胶水代码。
测试中的 Hilt
Hilt 对测试支持很好。可以针对测试替换某些依赖:
@UninstallModules(NetworkModule::class)@HiltAndroidTestclass ArticleRepositoryTest {@Injectlateinit var repository: ArticleRepository@Testfun testGetArticles() = runTest {val articles = repository.getArticles()assertTrue(articles.isNotEmpty())}}
也可以用 @TestInstallIn 在测试时替换整个 Module:
@Module@TestInstallIn(components = [SingletonComponent::class],replaces = [NetworkModule::class])object FakeNetworkModule {@Provides@Singletonfun provideApiService(): ApiService {return FakeApiService()}}
这样测试时用的是假接口实现,不需要真实网络请求。
常见坑
忘记加 @AndroidEntryPoint——Activity 或 Fragment 里用 @Inject 之前必须先标这个注解,否则注入不会生效,变量为 null。
Module 忘记 @InstallIn——@Module 必须配合 @InstallIn 指定安装到哪个组件,否则编译报错。
在 SingletonComponent 中使用 Activity Context——全局单例的生命周期远超 Activity,持有 Activity Context 会泄漏。需要 Context 时用 @ApplicationContext。
ViewModel 没有用 @HiltViewModel——直接在 ViewModel 构造函数写 @Inject 配合 by viewModels() 不行,ViewModel 必须用 @HiltViewModel 标注。
循环依赖——A 依赖 B,B 依赖 A,Hilt 在编译期会检测到并报错。遇到时需要重新审视架构设计,通常意味着职责划分有问题。
第三方库对象忘记提供 Module——像 Gson、Picasso、Firebase 这些第三方库的实例不能 @Inject constructor,必须通过 @Module + @Provides 提供。
kapt/ksp 增量编译问题——偶尔遇到编译不通过但代码没问题的情况,Clean + Rebuild 通常能解决。
总结
Hilt 的核心用法其实可以归纳得很简洁:@HiltAndroidApp 放在 Application 上,启动 Hilt;@AndroidEntryPoint 放在需要注入的 Android 组件上;@Inject constructor 标记普通类的构造函数;@Module + @InstallIn + @Provides 提供不能直接构造的对象;@Binds 简洁地绑定接口和实现;@HiltViewModel 配合 by viewModels() 或 hiltViewModel() 注入 ViewModel;@Singleton 控制全局单例,其他作用域按需使用;@Qualifier 区分同类型的多个实现。
依赖注入不是为了让代码"看起来高级",而是为了解耦、方便测试、统一对象管理。Hilt 把这件事的门槛降到了很低,大部分 Android 项目都可以直接用起来。下一篇会聊 Paging 3 分页加载,它和 Hilt、ViewModel、Flow 配合后,列表页的数据加载会变得非常清晰。
游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。
同类文章
刚刚,OpenClaw和Cursor杀入手机!
AI Agent,真的开始从电脑里“跑出来”了。以前我们用 Agent,基本离不开网页、IDE、终端、云环境。你想让它写代码、查资料、改项目、跑任务,很多时候还得坐在工位前盯着。但现在不一样了。OpenClaw 推出了 iOS 和安卓原生 App,手机可以变成私有 Agent 网络里的一个移动节点。
幻灯片排版优化AI智能助手,节省时间与精力
说起来,今天想和大家聊聊一个特别实在的话题:怎么用AI工具把PPT排版效率提上去,真正省下时间和精力。谁不想在忙忙碌碌的工作里找到点儿省事的诀窍呢?我有个朋友,为了准备一次重要汇报,连着熬了三个晚上折腾PPT,最后出来的效果也就是勉强及格。要是当时他能用上AI工具,结果会不会完全不一样?PPT排版优
AI排版软件让文档制作轻松又高效
AI智能排版工具通过自动识别文档结构、调整格式,显著提升排版效率。实际案例显示,文档处理时间可缩短约50%,项目交付效率提高40%。其功能涵盖自动排版、模板库、智能校对等,重构了文档制作流程,使用户专注内容创作,提升专业形象与市场竞争力。
Karpathy晒邮件曝光注意力机制真正起源:10年前三项独立研究
2014年,三项研究几乎同时独立提出注意力机制:DzmitryBahdanau在YoshuaBengio实验室开发出RNNSearch(后称注意力),AlexGraves和JasonWeston团队也发表了类似机制。该思想源于解决循环神经网络信息瓶颈的需求,采用可微加权平均,成为深度学习核心算法。
如何选择AI排版工具与技巧提升内容创作效率
AI排版工具推荐与技巧:如何提升内容创作效率与视觉设计效果其实,AI排版早已成为内容创作领域的热门话题。在信息爆炸的时代,大家都想知道如何让内容在海量信息中脱颖而出。简单来说,AI排版就是借助人工智能技术自动化处理文本、图像等内容的布局与设计。不妨想象一下:星巴克菜单上那些赏心悦目的排版,背后可能就
- 日榜
- 周榜
- 月榜
相关攻略
2026-07-01 16:26
2026-07-01 16:23
2026-07-01 16:23
2026-07-01 16:23
2026-07-01 16:22
2026-07-01 16:22
2026-07-01 16:21
2026-07-01 16:21
热门教程
- 游戏攻略
- 安卓教程
- 苹果教程
- 电脑教程
热门话题

