Hilt入门

Hilt 是什么

Hilt 是 Android 的依赖项注入库,可减少在项目中执行手动依赖项注入的样板代码。执行手动依赖项注入要求您手动构造每个类及其依赖项,并借助容器重复使用和管理依赖项。

Hilt 通过为项目中的每个 Android 类提供容器并自动管理其生命周期,提供了一种在应用中使用 DI(依赖项注入)的标准方法。Hilt 在热门 DI 库 Dagger 的基础上构建而成,因而能够受益于 Dagger 的编译时正确性、运行时性能、可伸缩性和 Android Studio 支持。

依赖注入是什么

一个类里面有一个变量,这个变量就是这个类的依赖。然后通过外部注入对这个变量进行赋值,这种就叫做依赖注入

工厂、Builder模式、带参数的构造函数这些都属于依赖注入

引入Hilt

首先,将 hilt-android-gradle-plugin 插件添加到项目的根级 build.gradle 文件中:

buildscript {
   ...
   dependencies {
   ...
   classpath 'com.google.dagger:hilt-android-gradle-plugin:2.28-alpha'
 }
}

然后,应用 Gradle 插件并在 app/build.gradle 文件中添加以下依赖项:

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 使用 Java 8 功能。如需在项目中启用 Java 8,请将以下代码添加到 app/build.gradle 文件中:

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

Hilt基本使用

  • @HiltAndroidApp
    @HiltAndroidApp 将会触发 Hilt 的代码生成,作为程序依赖项容器的基类
    生成的 Hilt 依附于 Application 的生命周期,他是 App 的父组件,提供访问其他组件的依赖
    所有使用 Hilt 的应用都必须包含一个带有 @HiltAndroidApp 注释的 Application 类。
    @HiltAndroidApp 会触发 Hilt 的代码生成操作,生成的代码包括应用的一个基类,该基类充当应用级依赖项容器。

    @HiltAndroidApp
    class ExampleApplication : Application() { ... }
    
  • 在 Application 中配置好后,就可以使用 Hilt 提供的组件了;组件包含 Application,Activity,Fragment,View,Service 等。

  • @AndroidEntryPoint
    创建一个依赖容器,该容器遵循 Android 的生命周期类,目前支持的类型是: Activity, Fragment, View, Service, BroadcastReceiver.

    @AndroidEntryPoint
    class MainActivity : AppCompatActivity() 
    
  • @Inject
    使用 @Inject 来告诉 Hilt 如何提供该类的实例,常用于构造方法,非私有字段,方法中。
    Hilt 有关如何提供不同类型的实例信息也称之为绑定

    @Inject
    lateinit var orderManager: OrderManager
    class OrderManager @Inject constructor(private val addressInfo: AddressInfo) {
    
       fun payOrder() {
          println( "payOrder()执行了")
       }
    }
    

接口注入

  • @Module
    module 是用来提供一些无法用构造@Inject 的依赖,如第三方库,接口,build 模式的构造等
    使用 @Module 注解的类,需要使用 @InstallIn 注解指定 module 的范围
    增加了 @Module 注解的类,其实代表的就是一个模块,并通过指定的组件来告诉在那个容器中可以使用绑定安装。

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

    @Module
    @InstallIn(ApplicationComponent::class)
    abstract class PayModule
    
  • @Binds:必须注释一个抽象函数,抽象函数的返回值是实现的接口。通过添加具有接口实现类型的唯一参数来指定实现。

首先需要一个接口,和一个实现类

interface PayMethod {
    fun startPay()
}

class WxPay @Inject constructor() : PayMethod {
     override fun startPay() {
     println("WxPay start.")
   }
}

接着就需要新建一个 Module。用来实现接口的注入

@Module
@InstallIn(ApplicationComponent::class)
abstract class PayModule {
   @Binds
   abstract fun bindWxPay(wxPay: WxPay): PayMethod
}

注意:这个 Module 是抽象的。

使用如下:

 @Inject
 lateinit var wxPay: PayMethod

 fun payOrder() {
   wxPay.startPay()
   println("print address ${addressInfo.province}")
   wxPay.getPayResult()
 }

给相同类型注入不同的实例

还是上面的 PayMethod 接口,有两个不同的实现,如下:

class WxPay @Inject constructor() : PayMethod {
     override fun startPay() {
     println("WxPay start.")
}

 override fun getPayResult() {
     println("WxPay getPayResult.")
 }
}

class ZfbPay @Inject constructor() : PayMethod {

 override fun startPay() {
   println("ZfbPay start.")
 }

 override fun getPayResult() {
   println("ZfbPay getPayResult.")
 }
}

接着定义两个注解

@Qualifier
annotation class BindWxPay

@Qualifier
annotation class BindZfbPay

然后修改 Module ,在 module 中用来标记相应的依赖。

@Module
@InstallIn(ApplicationComponent::class)
abstract class PayModule {

   @BindWxPay
   @Binds
   abstract fun bindWxPay(wxPay: WxPay): PayMethod

   @BindZfbPay
   @Binds
   abstract fun bindZfbPay(zfbPay: ZfbPay): PayMethod
}

最后使用如下:

 @BindWxPay
 @Inject
 lateinit var wxPay: PayMethod

 @BindZfbPay
 @Inject
 lateinit var zfbPay: PayMethod

 fun payOrder() {
   wxPay.startPay()
   zfbPay.startPay()
   wxPay.getPayResult()
   zfbPay.getPayResult()
 }

Hilt还提供了2个预置Qualifier限定符@ActivityContext和@ApplicationContext ,可以直接作为@Provides方法或@Inject构造的参数使用。

class AnalyticsAdapter @Inject constructor(

   @ActivityContext private val context: Context,

   private val service: AnalyticsService

) { ... }

第三方组件注入

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

Hilt 支持最常见的 Android 类 Application、Activity、Fragment、View、Service、BroadcastReceiver 等等,但是您可能需要在Hilt 不支持的类中执行依赖注入,在这种情况下可以使用 @EntryPoint 注解进行创建,Hilt 会提供相应的依赖。

Hilt 中的组件(Compenent)、生命周期、作用域

使用 @Module 注解的类,需要使用 @Installin 注解来指定 module 的范围。

例如 @InstallIn(ApplicationComponent::class) 注解的 Module 就会绑定到 Application 的生命周期上。

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

Hilt 组件 对应 Android 类活动的范围
ApplicationComponent Application
ActivityRetainedComponent ViewModel
ActivityComponent Activity
FragmentComponent Fragment
ViewComponent View
ViewWithFragmentComponent View annotated with @WithFragmentBindings
ServiceComponent Service

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


Hilt 会根据相应的 Android 类生命周期自动创建和销毁组件的实例,对应关系如下:

Hilt 提供的组件 创建对应的生命周期 结束对应的生命周期 作用域
ApplicationComponent Application#onCreate() Application#onDestroy() @Singleton
ActivityRetainedComponent Activity#onCreate() Activity#onDestroy() @ActivityRetainedScope
ActivityComponent Activity#onCreate() Activity#onDestroy() @ActivityScoped
FragmentComponent Fragment#onAttach() Fragment#onDestroy() @FragmentScoped
ViewComponent View#super() View destroyed @ViewScoped
ViewWithFragmentComponent View#super() View destroyed @ViewScoped
ServiceComponent Service#onCreate() View destroyed @ViewScoped

@InstallIn模块中确定绑定范围时,绑定上的范围必须与component的范围匹配。例如,@InstallIn(ActivityComponent.class)模块内的绑定只能用限制范围@ActivityScoped

例如我们需要在App中共享OkHttp的配置:

@Module
@InstallIn(ApplicationComponent::class)
class NetworkModule {

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

默认情况下,Hilt 中的所有绑定都未限定作用域。这意味着,每当应用请求绑定时,Hilt 都会创建所需类型的一个新实例

ViewModel

图 1. Android 应用的应用图表模型

各个类之间的依赖关系可以表示为图表,其中每个类都连接到其所依赖的类。所有类及其依赖关系的表示法便构成了应用图表。在图 1 中,您可以看到应用图表的抽象呈现。当 A 类 (ViewModel) 依赖于 B 类 (Repository) 时,有一条从 A 指向 B 的直线表示该依赖关系。

依赖项注入有助于建立这些链接并使您可以更换实现以进行测试。例如,在测试依赖于代码库的 ViewModel 时,您可以通过伪造或模拟传递 Repository 的不同实现,以测试不同的情形。

对于ViewModel这种常用Jetpack组件,Hilt专门为其提供了一种独立的依赖注入方式

dependencies {
   ...
   implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02'
   kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
}


class MyViewModel @ViewModelInject constructor(private val repository: Repository) : ViewModel() {

   fun doWork() {
       repository.doRepositoryWork()
   }
}

参考资料:https://developer.android.google.cn/training/dependency-injection/hilt-android

你可能感兴趣的:(Hilt入门)