Hilt 是什么
Hilt 是 Android 的依賴項注入庫,可減少在項目中執(zhí)行手動依賴項注入的樣板代碼。執(zhí)行手動依賴項注入要求您手動構造每個類及其依賴項,并借助容器重復使用和管理依賴項。
Hilt 通過為項目中的每個 Android 類提供容器并自動管理其生命周期,提供了一種在應用中使用 DI(依賴項注入)的標準方法。Hilt 在熱門 DI 庫 Dagger 的基礎上構建而成,因而能夠受益于 Dagger 的編譯時正確性、運行時性能、可伸縮性和 Android Studio 支持。
依賴注入是什么
一個類里面有一個變量,這個變量就是這個類的依賴。然后通過外部注入對這個變量進行賦值,這種就叫做依賴注入
工廠、Builder模式、帶參數(shù)的構造函數(shù)這些都屬于依賴注入
引入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 將會觸發(fā) Hilt 的代碼生成,作為程序依賴項容器的基類
生成的 Hilt 依附于 Application 的生命周期,他是 App 的父組件,提供訪問其他組件的依賴
所有使用 Hilt 的應用都必須包含一個帶有@HiltAndroidApp注釋的Application類。
@HiltAndroidApp會觸發(fā) Hilt 的代碼生成操作,生成的代碼包括應用的一個基類,該基類充當應用級依賴項容器。@HiltAndroidApp class ExampleApplication : Application() { ... } 在 Application 中配置好后,就可以使用 Hilt 提供的組件了;組件包含 Application,Activity,F(xiàn)ragment,View,Service 等。
-
@AndroidEntryPoint
創(chuàng)建一個依賴容器,該容器遵循 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()執(zhí)行了") } }
接口注入
@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:必須注釋一個抽象函數(shù),抽象函數(shù)的返回值是實現(xiàn)的接口。通過添加具有接口實現(xiàn)類型的唯一參數(shù)來指定實現(xiàn)。
首先需要一個接口,和一個實現(xiàn)類
interface PayMethod {
fun startPay()
}
class WxPay @Inject constructor() : PayMethod {
override fun startPay() {
println("WxPay start.")
}
}
接著就需要新建一個 Module。用來實現(xiàn)接口的注入
@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 接口,有兩個不同的實現(xiàn),如下:
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構造的參數(shù)使用。
class AnalyticsAdapter @Inject constructor(
@ActivityContext private val context: Context,
private val service: AnalyticsService
) { ... }
第三方組件注入
- @Provides
常用于被 @Module 注解標記類的內(nèi)部方法上。并提供依賴項對象。
Hilt 支持最常見的 Android 類 Application、Activity、Fragment、View、Service、BroadcastReceiver 等等,但是您可能需要在Hilt 不支持的類中執(zhí)行依賴注入,在這種情況下可以使用 @EntryPoint 注解進行創(chuàng)建,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 會根據(jù)相應的 Android 類生命周期自動創(chuàng)建和銷毀組件的實例,對應關系如下:
| Hilt 提供的組件 | 創(chuàng)建對應的生命周期 | 結束對應的生命周期 | 作用域 |
|---|---|---|---|
| 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)模塊內(nèi)的綁定只能用限制范圍@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 都會創(chuàng)建所需類型的一個新實例
ViewModel

各個類之間的依賴關系可以表示為圖表,其中每個類都連接到其所依賴的類。所有類及其依賴關系的表示法便構成了應用圖表。在圖 1 中,您可以看到應用圖表的抽象呈現(xiàn)。當 A 類 (ViewModel) 依賴于 B 類 (Repository) 時,有一條從 A 指向 B 的直線表示該依賴關系。
依賴項注入有助于建立這些鏈接并使您可以更換實現(xiàn)以進行測試。例如,在測試依賴于代碼庫的 ViewModel 時,您可以通過偽造或模擬傳遞 Repository 的不同實現(xiàn),以測試不同的情形。
對于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