這篇記錄下 Hilt 最基本的使用方法。
Hilt 是基于 Dagger 開發(fā)的依賴注入框架。我們知道 Dagger 是 Java 開發(fā)中無可否認(rèn)的功能最為強(qiáng)大的依賴注入框架罐盔,但是它的缺點(diǎn)是使用起來比較復(fù)雜汰寓,尤其是對(duì)于初學(xué)者而言芍锦,學(xué)習(xí)曲線異常陡峭斤儿。而依賴注入框架在 Android 開發(fā)中也是一個(gè)非常重要的工具,因此驳癌,在 Kotlin 成為了 Android 開發(fā)者的首選語言之后,開源社區(qū)中誕生了許多基于 Kotlin 依賴注入框架役听,比如 Koin 和 Kodein颓鲜。谷歌當(dāng)然也注意到了這一點(diǎn),所以也基于 Dagger 推出了更簡單易上手的 Hilt典予,它的主要優(yōu)勢(shì)是:
- 基于 Android 簡化了 Dagger 相關(guān)的基礎(chǔ)架構(gòu)甜滨;
- 提供了一組標(biāo)準(zhǔn)的 Component 和 Scope 以簡化使用、提升可讀性以及便于代碼共享瘤袖;
- 簡化針對(duì)不同的構(gòu)建類型(比如測(cè)試衣摩、調(diào)試或發(fā)布類型)配置不同的綁定。
之所以能做到以上這幾點(diǎn)捂敌,是因?yàn)?Hilt 自動(dòng)幫我們做了很多工作艾扮,比如自動(dòng)生成用于和 Android Framwork 綁定的 Component/Scoped annotations/Bindings/Qualifier 等,而如果使用 Dagger 的話占婉,這些都是需要我們自己手動(dòng)編寫代碼來管理的泡嘴。
Hilt 的基本使用
使用方式上,Hilt 和 Dagger 相比最明顯的區(qū)別是逆济,不再需要定義 Component酌予,對(duì)于每一個(gè) Android 基礎(chǔ)類,Hilt 會(huì)自動(dòng)為它生成對(duì)應(yīng)的 Component奖慌,并且會(huì)根據(jù)安卓組件的生命周期來創(chuàng)建和銷毀抛虫。如下:
Hilt 組件 | 注入器面向的對(duì)象 |
---|---|
ApplicationComponent |
Application |
ActivityRetainedComponent |
ViewModel |
ActivityComponent |
Activity |
FragmentComponent |
Fragment |
ViewComponent |
View |
ViewWithFragmentComponent |
帶有 @WithFragmentBindings 注釋的 View
|
ServiceComponent |
Service |
因此,對(duì)于一個(gè)最簡單的 MVVM 項(xiàng)目而言简僧,使用 Hilt 做依賴注入一般需要按照以下的步驟:
- 添加 Hilt 插件和依賴建椰,對(duì)于每個(gè) module 都要單獨(dú)添加
- 使用
@HiltAndroidApp
標(biāo)注你自定義的Application
- 使用
@AndroidEntryPoint
標(biāo)注你的Fragment
或者Activity
- 使用
@HiltViewModel
標(biāo)注你的 ViewModel 類,以及用@Inject
標(biāo)注構(gòu)造器 - 使用
@Inject
標(biāo)注需要注入的依賴涎劈,比如 Repository 等 - 定義 Hilt 模塊广凸,用于提供無法直接注入的依賴,比如接口類和外部的依賴類等
- 使用
@InstallIn
標(biāo)注該模塊的作用范圍 - 使用
@Provides
標(biāo)注提供每個(gè)依賴的方法 - 使用
@Binds
標(biāo)注需要注入依賴的接口和具體實(shí)現(xiàn)(通過抽象類和抽象方法)
- 使用
具體例子可以參考我的開源小項(xiàng)目:Jithub
模塊和組件
雖然 Hilt 大大簡化了依賴注入的使用蛛枚,但是使用方式上和 Dagger 并沒有太大區(qū)別谅海,最基礎(chǔ)的組成部分依舊是模塊和組件。對(duì)于某個(gè) Hilt 模塊蹦浦,如果我們想要注入多個(gè)相同類型的依賴扭吁,同樣需要通過定義限定符來實(shí)現(xiàn)。
使用注解定義限定符(例子來自官方文檔):
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient
除此之外,我們還可以使用 Hilt 自帶的限定符侥袜,比如 @ActivityContext
和 @ApplicationContext
等蝌诡。
組件的使用細(xì)節(jié)
之前提到過對(duì)于不同的 Android 類,Hilt 會(huì)為之生成對(duì)應(yīng)的組件枫吧,我們?cè)谀K中通過 @InstalledIn
引用組件浦旱,然后 Hilt 會(huì)將模塊安裝到對(duì)應(yīng)的組件中,最后再把依賴注入到組件中九杂。
除此之外颁湖,每個(gè)組件都有自己的生命周期,而且我們還可以為組件限定作用域例隆。不同的組件作用域內(nèi)可使用的依賴也不同甥捺,比如 @FragmentScoped
作用域內(nèi)的依賴可以在 @ActivityScoped
的組件中使用,但是無法在 @ViewScoped
的組件中使用镀层。
Android 類 | 生成的組件 | 作用域 |
---|---|---|
Application |
ApplicationComponent |
@Singleton |
View Model |
ActivityRetainedComponent |
@ActivityRetainedScope |
Activity |
ActivityComponent |
@ActivityScoped |
Fragment |
FragmentComponent |
@FragmentScoped |
View |
ViewComponent |
@ViewScoped |
帶有 @WithFragmentBindings 注釋的 View
|
ViewWithFragmentComponent |
@ViewScoped |
Service |
ServiceComponent |
@ServiceScoped |
其它細(xì)節(jié)
如果需要在 Hilt 不支持的類中注入依賴镰禾,比如 ContentProvider
,我們可以通過創(chuàng)建 EntryPoint
來訪問這些依賴唱逢。
通過 @EntryPoint
創(chuàng)建依賴入口(通常是一個(gè)接口)吴侦,然后在其中定義方法提供所需要的依賴,再通過 @InstalledIn
來定義安裝到哪個(gè)組件惶我。另外妈倔,訪問 EntryPoint
依賴也和普通的依賴不同,我們需要通過之前定義好的 EntryPoint
接口來訪問依賴項(xiàng)绸贡。
val entryPointInterface = EntryPointAccessors.fromXxx(Application/Activity/Fragment/Context, EntryPointInterface::class.java)
EntryPointAccessors
中包含不同的創(chuàng)建方法盯蝴,對(duì)應(yīng)于創(chuàng)建不同的組件,比如 EntryPointAccessors.fromApplication()
對(duì)應(yīng)于 SingletonComponent
听怕,fromActivity()
對(duì)應(yīng)于 ActivityComponent
等捧挺。創(chuàng)建 EntryPoint
接口對(duì)象之后,我們就可以通過它來訪問依賴了尿瞭。
小結(jié)
可以看到闽烙,Hilt 大大簡化了傳統(tǒng)依賴注入框架的使用方式,但是核心功能基本和 Dagger 保持一致声搁,因此黑竞,開發(fā)人員可以將更多的注意力放在開發(fā)上,從而提升開發(fā)效率疏旨。