Dagger-Hilt Android的依赖注入框架


Hilt 是干什么的?

它是 Google 为Android开发提供的场景化依赖库,皆在减少项目中进行的手动依赖注入。

Hilt 为项目中的每个 Android 类提供容器并自动管理它们的生命周期,为应用程序提供了 DI的标准方法。它是从 Dagger 库的基础上进行构建的,因为 Dagger提供的编译时正确性、运行时性能、可伸缩性并且从AndroidStudio支持Dagger中获益。

相比Dagger,Hilt有那些优化?

Hilt的实现要比Dagger简单的多,使用Dagger实现依赖注入,需要去编写modules、components等等。每次去创建一个新的Android组件,比如 Activity、Fragment时,我们都需要将它们手动添加到modules中。

使用 Hilt 前的准备工作

  • 添加依赖 在项目的根目录下 build.gradle 文件
buildscript {
    ...
    dependencies {
        ...
        classpath "com.google.dagger:hilt-android-gradle-plugin:2.28.3-alpha"
    }
}
  • 在项目的应用级目录下
...
apply plugin: 'kotlin-kapt'
apply plugin: 'dagger.hilt.android.plugin'

android {
    ...
}

dependencies {
    implementation "com.google.dagger:hilt-android:2.28-alpha"
    kapt "com.google.dagger:hilt-android-compiler:2.28-alpha"
}

Hilt 使用Java8的功能,所以我们在项目中启用它,应用模块下 build.gradle 文件添加代码。

android {
  ...
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }

    // For Kotlin projects
    kotlinOptions {
        jvmTarget = "1.8"
    }
}

注意

在 Kotlin 项目中,需要添加 kotlinOptions,否则ViewModel会编译不通过。

需要注意使用hilt 和data binding,需要AndroidStudio的版本必须>=4.0。

Application 是 App 的入口,所有使用Hilt的App必须包含一个使用@HiltAndroidApp注解的Application

@HiltAndroidApp
class HiltApplication : Application() {
    /**
     * 1. 所有使用 Hilt 的 App 必须包含一个使用 @HiltAndroidApp 注解的 Application
     * 2. @HiltAndroidApp 将会触发 Hilt 代码的生成,包括用作应用程序依赖项容器的基类
     * 3. 生成的 Hilt 组件依附于 Application 的生命周期,它也是 App 的父组件,提供其他组件访问的依赖
     * 4. 在 Application 中设置好 @HiltAndroidApp 之后,就可以使用 Hilt 提供的组件了,
     *    Hilt 提供的 @AndroidEntryPoint 注解用于提供 Android 类的依赖(Activity、Fragment、View、Service、BroadcastReceiver)等等
     *    Application 使用 @HiltAndroidApp 注解
     */
}
  1. @HiltAndroidApp会触发Hilt代码的生成,包括用作应用程序依赖容器的基类
  2. 生成的Hilt组件依附于Application的生命周期,它也是App的父组件,提供其他组件访问的依赖。

使用 Hilt 进行依赖注入

注入 HiltSimple 并在 Application 中调用它的doSomething方法。

class HiltSimple @Inject constructor() {
    fun doSomething() {
        Log.e(TAG, "----doSomething----")
    }
}

@HiltAndroidApp
class HiltApplication : Application() {
    @Inject
    lateinit var mHiltSimple: HiltSimple

    override fun onCreate() {
        super.onCreate()
        mHiltSimple.doSomething()
    }
}

Hilt 需要知道如何从相对应的组件中提供必要的依赖实例。使用@Inject注解来告诉Hilt如何提供该类的实例,@Inject 常用于构造函数、非私有字段、方法。

Hilt 常用注解的含义

@HiltAndroidApp

1 所有使用HIlt的App必须包含一个使用@HiltAndroidApp注解的Application。

2 @HiltAndroidApp注解将会触发Hilt代码的生成,作为应用程序依赖项容器的基类。

3 生成的Hilt组件依附于Application的生命周期,它也是App的父组件,提供其他组件访问的依赖。

4 在Application中设置号@HiltAndroidApp之后,就可以使用Hilt提供的组件了,组件包含Applicaiton、Activity、Fragment等。

@AndroidEntryPoint

Hilt 提供的@AndroidEntryPoint注解用于提供Android类的依赖(Activity、Fragment、View、Service、BroadcastReceiver)

特殊的Application使用 @HiltAndroidApp注解。

  • Activity:支持ComponentActivity的子类例如FragmentActivity、AppCompatActivity等。

  • Fragment:支持 androidx.Fragment包下的Fragment。

  • View

  • Service

  • BroadcastReceiver

注意

在使用@AndroidEntryPoint在非ComponentActivity子类上注解,例如Activity则会抛出异常。

Activities annotated with @AndroidEntryPoint must be a subclass of androidx.activity.ComponentActivity. (e.g. FragmentActivity, AppCompatActivity, etc.)

使用@AndroidEntryPoint注解时,必须在它的依赖的Android类添加同样的注解,例如Fragment中添加@AndroidEntryPoint注解,必须在Fragment依赖的Activity上也添加@AndroidEntryPoint注解,否则会抛出一样。

java.lang.IllegalStateException: Hilt Fragments must be attached to an @AndroidEntryPoint Activity. Found: class com.hi.dhl.hilt.MainActivity

@Module

常用于创建依赖类的对象(例如第三方库 OkHttp、Retrofit等等),使用@Module注解的类,需要使用@InstallIn注解指定范围module。

@Module
@InstallIn(ApplicationComponent::class)
// 这里使用了 ApplicationComponent,因此 NetworkModule 绑定到 Application 的生命周期。
object NetworkModule {
}

@InstallIn

使用@Module注入的类,使用@InstallIn注解指定module的范围,例如使用@InstallIn(ActivityComponent::class)注解的module会绑定到Activity的生命周期上。

Hilt 提供了以下组件来绑定依赖与对应的Android类的活动范围。

Hilt 提供组件 对应的Android类活动范围 作用域
ApplicationComponent Application @Singleton
ActivityRetainedComponent ViewModel @ActivityRetainedScope
ActivityComponent Activity @ActivityScoped
FragmentComponent Fragment @FragmentScoped
ViewComponent View @ViewScoped
ViewWithFragmentComponent View annotated with @WithFragmentBindings @ViewScoped
ServiceComponent Service @ServiceScoped

注意

Hilt 没有为 broadcast receivers 提供组件,因为Hilt直接从ApplicationComponent注入broadcast receivers。

Hilt 会根据相应的 Android 类生命周期自动创建和销毁生成的组件类的实例。如下。

Hilt 提供的组件 创建对应的生命周期 销毁对应的生命周期
ApplicationComponent Application#onCreate() Application#onDestory()
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy()
ActivityComponent Activity#onCreate() Activity#OnDestroy()
FragmentComponent Fragment#OnAttach() Fragment#onDestroy()
ViewComponent View#super() View destroyed
ViewWithFragmentComponent View#super() View destroyed
ServiceComponent Service#onCreate() Service#onDestroy()

@Provides

常用于被 @Module 注解标记类的内部方法,并提供依赖项对象。

@Module
@InstallIn(ApplicationComponent::class)
// 这里使用了 ApplicationComponent,因此 NetworkModule 绑定到 Application 的生命周期。
object NetworkModule {

    /**
     * @Provides 常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。
     * @Singleton 提供单例
     */
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .build()
    }
}

Hilt 同 第三方组件一起使用

如果你要在项目中添加第三方依赖,需要使用@Module注解,使用@Module注解的普通类,在其中创建第三方依赖的对象。

@Module
@InstallIn(ApplicationComponent::class)
// 这里使用了 ApplicationComponent,因此 NetworkModule 绑定到 Application 的生命周期。
object NetworkModule {

    /**
     * @Provides 常用于被 @Module 注解标记类的内部的方法,并提供依赖项对象。
     * @Singleton 提供单例
     */
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .build()
    }

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

    @Provides
    @Singleton
    fun provideGitHubService(retrofit: Retrofit): GitHubService {
        return retrofit.create(GitHubService::class.java)
    }
}
  • @Module 常用于创建依赖类对象(如OkHttp、Retrofit等等)。
  • 使用 @Module注入的类,需要使用@InstallIn注解指定module的范围,会绑定到Android类对应的生命周期上。
  • @Provides 常用于标记类的内部方法,并提供依赖项对象。

当需要上下文是使用的注解(预定义限定符)

​ HIlt提供了预定义限定符。例如,当你需要使用应用或者Activity的Context类时,Hilt提供了@ApplicationContext@ActivityContext限定符。

假如,当前这个类需要Activity的上下文。

class Test @Inject constructor(
    @ActivityContext private val context: Context,
    private val service: AnalyticsService
) { ... }

引用

Jetpack 新成员 Hilt 实践(一)启程过坑记

Jetpack 新成员 Hilt 与 Dagger 大不同(三)落地篇

Hilt 中的预定义限定符

JavaDoc-Glide


文章作者: TheCara
版权声明: 本博客所有文章除特別声明外,均采用 CC BY-NC 4.0 许可协议。转载请注明来源 TheCara !
  目录