10、Hilt依赖注入:Hilt基础、@HiltAndroidApp与@AndroidEntryPoint、@Module与@Provides

依赖注入(DI)这个概念,说实话,刚入行那会儿我觉得挺玄乎的。不就是 new 个对象嘛,搞那么复杂干嘛?直到我接手了一个有十几个模块的项目,每次改个构造参数要翻遍几十个文件……嗯,那酸爽,谁改谁知道。

Hilt 是 Google 官方基于 Dagger 打造的 Android 依赖注入框架。说白了,它就是帮你自动生成那些繁琐的「工厂类」和「容器代码」。你只需要告诉它「我要什么」和「怎么创建」,剩下的脏活累活,Hilt 全包了。

核心思想:Hilt 通过编译期注解处理,在 APT 阶段生成依赖图。运行时你拿到的对象,都是经过完整依赖链装配好的。省心,也省 bug。

10.1 Hilt 的三大基石

要理解 Hilt,先记住三个角色:

  • 容器 —— 谁负责管理对象的生命周期?
  • 入口 —— 哪些 Android 类可以「被注入」?
  • 配方 —— 当对象不是自己构造时,怎么告诉 Hilt 去创建?

我个人习惯把 Hilt 想象成一个「智能工具箱」。你往里面放工具(对象),然后告诉它「这个工具给 Activity 用」、「那个工具全局共享」。用的时候,直接伸手拿就行。

Hilt 依赖注入核心架构 Hilt 容器 @HiltAndroidApp Application 级容器 @AndroidEntryPoint Activity / Fragment 入口 @Module + @Provides 第三方对象装配 编译期生成依赖图 → 运行时按需注入 APT 注解处理 + 工厂类自动生成

10.2 @HiltAndroidApp —— 一切的起点

这是 Hilt 的「总开关」。你需要在 Application 类上加上这个注解。

@HiltAndroidApp
class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        // 这里不需要任何 Hilt 初始化代码
    }
}

加上这个注解后,Hilt 会在编译期生成一个 MyApplication_HiltComponents 类。它负责管理整个应用的组件树。你想想看,如果没有这个注解,Hilt 连「从哪里开始构建容器」都不知道。

💡 个人经验:我早期有个项目忘了加 @HiltAndroidApp,结果所有 @AndroidEntryPoint 都报错。排查了半天才发现是 Application 没注解。所以我的习惯是:新建项目第一件事,就是给 Application 打上这个注解。

10.3 @AndroidEntryPoint —— 让 Android 组件「可注入」

Activity、Fragment、Service、BroadcastReceiver 这些 Android 组件,默认是不认识 Hilt 的。你需要用 @AndroidEntryPoint 告诉 Hilt:「嘿,这个类需要注入依赖」。

@AndroidEntryPoint
class MainActivity : AppCompatActivity() {

    @Inject lateinit var userRepository: UserRepository

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        // userRepository 已经可用,无需手动创建
    }
}

这里有个细节要注意:@AndroidEntryPoint 只能用在直接或间接继承自 ComponentActivity 的类上。如果你用了一个自定义的 BaseActivity,它没有继承 AppCompatActivity,那就不行。

⚠️ 避坑指南:我曾经在 Fragment 里用 @AndroidEntryPoint,但忘记给它的宿主 Activity 也加上同样的注解。结果运行时直接崩溃,错误信息是「cannot be created without the parent activity being annotated with @AndroidEntryPoint」。记住:Fragment 的依赖注入依赖于 Activity 的 Hilt 组件。

支持的 Android 组件类型:

组件类型 是否支持 生命周期范围
Application ✅(通过 @HiltAndroidApp) 单例
Activity Activity 生命周期
Fragment Fragment 生命周期
Service Service 生命周期
BroadcastReceiver 每次广播回调
View View 生命周期

10.4 @Module 与 @Provides —— 当 Hilt 不会自己创建时

大部分情况下,Hilt 可以通过构造函数上的 @Inject 注解知道怎么创建对象。但遇到下面几种情况,Hilt 就懵了:

  • 对象来自第三方库(比如 Retrofit、OkHttp)
  • 对象需要 Builder 模式创建
  • 同一个接口需要多个不同的实现
  • 对象需要配置参数才能创建

这时候就需要 @Module@Provides 出场了。

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .build()
    }

    @Provides
    @Singleton
    fun provideRetrofit(client: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
}

这里有几个关键点:

  • @Module:告诉 Hilt 这是一个「配方集合」
  • @InstallIn:指定这个 Module 安装在哪个组件中。SingletonComponent 表示全局单例
  • @Provides:标记这个方法是一个「对象工厂」
  • @Singleton:表示这个对象在整个应用中只创建一次

🔑 核心理解:@Provides 方法的参数也会被 Hilt 自动注入。比如上面 provideRetrofit 需要 OkHttpClient,Hilt 会先调用 provideOkHttpClient 拿到实例,再传给 provideRetrofit。这就是「依赖链」的自动装配。

10.5 实战中的小技巧

我在实际项目中总结了几条经验,分享给你:

  1. Module 按功能拆分:不要把所有 @Provides 方法塞到一个大 Module 里。我习惯按层拆分:NetworkModule、DatabaseModule、RepositoryModule。这样好维护,也好测试。
  2. 善用 @Binds 替代 @Provides:如果只是把接口绑定到实现类,用 @Binds 更简洁。它比 @Provides 少创建一层包装,性能更好。
  3. 注意 @InstallIn 的作用域:如果你在 ActivityComponent 里提供了某个对象,那 Fragment 是拿不到的。作用域不匹配,编译期就会报错。
// @Binds 的典型用法
@Module
@InstallIn(SingletonComponent::class)
abstract class RepositoryModule {

    @Binds
    @Singleton
    abstract fun bindUserRepository(
        userRepositoryImpl: UserRepositoryImpl
    ): UserRepository
}

💡 我的习惯:每次写完 Module,我都会手动检查一下「这个对象应该活多久」。是跟着 Application 走?还是跟着 Activity 走?想清楚再选 @InstallIn。选错了,轻则内存泄漏,重则运行时崩溃。

10.6 小结

Hilt 的核心就三件事:

  • @HiltAndroidApp 搭好舞台
  • @AndroidEntryPoint 让组件入场
  • @Module + @Provides 准备好道具

这三板斧用熟了,依赖注入就不再是玄学,而是实实在在的「生产力工具」。你想想看,以前写个网络请求,要手动创建 OkHttpClient、Retrofit、ApiService……现在 Hilt 全帮你搞定了。代码干净了,测试也好写了,何乐而不为?


公众号:蓝海资料掘金营,微信deep3321