1 Hilt簡(jiǎn)介
Hilt 是 Android Jetpack中的依賴注入庫(kù)案糙,可減少項(xiàng)目代碼,用于模塊解耦靴庆。Hilt是在Dagger基礎(chǔ)上進(jìn)行二次封裝構(gòu)建的时捌,相對(duì)Dagger來說,代碼量更少炉抒,使用更簡(jiǎn)單端礼。不同的是,Dagger利用注解使用APT去生成輔助代碼佳镜,而Hilt是利用注解使用APT和ASM(字節(jié)碼插樁)去生成輔助代碼凡桥。
Hilt官網(wǎng):https://dagger.dev/hilt/
Google官網(wǎng)Hilt使用:https://developer.android.com/training/dependency-injection/hilt-android?hl=zh-cn
2 Hilt使用
2.1 引入依賴
根目錄build.gradle中添加hilt-android-gradle-plugin插件,最新版本可以在官網(wǎng)查看啊掏。
buildscript {
dependencies {
classpath 'com.google.dagger:hilt-android-gradle-plugin:2.41'
}
}
在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"
}
2.2 幾種常用注解
@Inject
用來標(biāo)注需要依賴獲取的對(duì)象迟蜜。
@Module
用來標(biāo)注提供依賴對(duì)象的類娜睛,也就是Module類,Module類中會(huì)有一個(gè)方法來提供依賴對(duì)象畦戒,在這個(gè)方法中可以對(duì)注入對(duì)象的有參構(gòu)造函數(shù)傳入?yún)?shù)或者進(jìn)行其他處理。
@Provides
用來標(biāo)注Module類中的提供依賴對(duì)象的方法進(jìn)行標(biāo)注纵潦,該方法在需要提供依賴時(shí)被調(diào)用邀层,從而把預(yù)先提供好的對(duì)象當(dāng)做依賴給標(biāo)注了@Inject 的變量賦值晴裹。
@HiltAndroidApp
用來標(biāo)注Application,這個(gè)是必須到,如果沒有該注解经磅,程序會(huì)崩潰。該注解會(huì)觸發(fā) Hilt 的代碼生成操作阿迈,生成的代碼包括應(yīng)用的一個(gè)基類苗沧,該基類充當(dāng)應(yīng)用級(jí)依賴項(xiàng)容器炭晒。
@AndroidEntryPoint
表示該類為接受依賴注入的對(duì)象,Hilt可以為帶有@AndroidEntryPoint注釋的Android類提供依賴項(xiàng)识樱。如果使用 @AndroidEntryPoint 為某個(gè) Android 類添加注釋震束,則還必須為依賴于該類的Android類添加注釋。例如割疾,如果為某個(gè)Fragment添加注釋宏榕,則還必須為使用該 Fragment 的所有 Activity 添加注釋。
@Binds
用來綁定接口和實(shí)現(xiàn)類担扑,會(huì)告知 Hilt 在需要提供接口的實(shí)例時(shí)要使用哪種實(shí)現(xiàn)。
@InstallIn
表示希望Hilt將該類注解到某處胚宦。比如BookModule類使用@InstallIn(ActivityComponent::class)枢劝,就表示BookModule中所有的額依賴項(xiàng)都可以在Activity中使用卜壕。
2.3 Hilt支持的類
Application(通過使用 @HiltAndroidApp)
Activity
Fragment
View
Service
BroadcastReceiver
2.4 Hilt為 Android 類生成的組件
對(duì)于可以從中執(zhí)行字段注入的每個(gè)Android類,都有一個(gè)關(guān)聯(lián)的 Hilt 組件鹤盒,可以 @InstallIn注釋中引用該組件侦副。每個(gè)Hilt組件負(fù)責(zé)將其綁定注入相應(yīng)的 Android 類。
Hilt組件 | 注入器面向的對(duì)象 |
---|---|
ApplicationComponent | Application |
ActivityRetainedComponent | ViewModel |
ActivityComponent | Activity |
FragmentComponent | Fragment |
ViewComponent | View |
ViewWithFragmentComponent | 帶有 @WithFragmentBindings 注釋的 View |
ServiceComponent | Service |
2.5 使用@Provides注入實(shí)例
創(chuàng)建Book對(duì)象尺碰,示例中將使用hilt在Activity中獲取對(duì)象亲桥。
data class Book(val name: String)
創(chuàng)建BookModule题篷,用來提供Book對(duì)象玻驻。BookModule需要用@Module來標(biāo)注,表示這是一個(gè)提供依賴注入對(duì)象的類户辫。然后用@InstallIn(ActivityComponent::class)來標(biāo)注嗤锉,表示依賴注入將作用于Activity。
@Module
@InstallIn(ActivityComponent::class)
class BookModule {
@Provides
fun provideBook(): Book {
return Book("三體")
}
}
創(chuàng)建兩個(gè)Activity奥额,分別在兩個(gè)Activity中打印獲取到的Book對(duì)象的hashCode。
@AndroidEntryPoint//標(biāo)記這是一個(gè)注入點(diǎn)
class FirstActivity : AppCompatActivity() {
private val TAG = "zhangmushui"
//執(zhí)行對(duì)象注入
@Inject
lateinit var book: Book
@Inject
lateinit var book2: Book
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_first)
findViewById<Button>(R.id.button).setOnClickListener {
startActivity(
Intent(
this,
SecondActivity::class.java
)
)
}
Log.d(TAG, "book hashCode: ${book.hashCode()}")
Log.d(TAG, "book2 hashCode: ${book2.hashCode()}")
}
}
@AndroidEntryPoint
class SecondActivity : AppCompatActivity() {
private val TAG = "zhangmushui"
@Inject
lateinit var book: Book
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
Log.d(TAG, "book3 hashCode: ${book.hashCode()}")
}
}
運(yùn)行程序韩肝,查看log哀峻。
2022-04-21 18:26:16.730 22743-22743/cn.zhangmushui.hilt D/zhangmushui: book hashCode: 639594
2022-04-21 18:26:16.730 22743-22743/cn.zhangmushui.hilt D/zhangmushui: book2 hashCode: 639594
2022-04-21 18:26:21.580 22743-22743/cn.zhangmushui.hilt D/zhangmushui: book3 hashCode: 639594
可以看到剩蟀,3個(gè)Book對(duì)象額HashCode一致切威,Hilt默認(rèn)的依賴注入對(duì)象是單例的。
2.6 使用@Binds注入接口實(shí)例
創(chuàng)建一個(gè)接口BookService缰冤。
interface BookService {
fun getBook()
}
實(shí)現(xiàn)這個(gè)接口烙无,打印一句話,注意需要用@Inject來標(biāo)注構(gòu)造方法。
class BookServiceImpl @Inject constructor() : BookService {
override fun getBook() {
Log.d("zhangmushui", "獲取到了一本書")
}
}
創(chuàng)建Module類乾戏,用@Binds將接口和實(shí)現(xiàn)類關(guān)聯(lián)鼓择。
@Module
@InstallIn(ActivityComponent::class)
abstract class BookModule {
@Binds
abstract fun bindBookService(bookServiceImpl: BookServiceImpl): BookService
}
在Activity中,只需要通過@Inject去依賴注入接口類即可念搬。
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var bookService: BookService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
bookService.getBook()
}
}
可以看到摆出,無需手動(dòng)實(shí)例化接口實(shí)現(xiàn)類,即可調(diào)用接口爷恳。
3 Hilt原理解析
Hilt使用APT和ASM技術(shù)温亲,通過注解去生成輔助類。原理和Dagger2類似栈虚,說直白點(diǎn)就是各個(gè)類使用對(duì)應(yīng)的注解,就會(huì)生成對(duì)應(yīng)的輔助類曼验,然后把依賴注入對(duì)象實(shí)例化的工作交給這些輔助類去做头镊,所以就只通過注解就能達(dá)到獲取到對(duì)象的目的。
詳細(xì)分析可以參照模塊解耦神器-Dagger2的使用和詳解 - 簡(jiǎn)書 (jianshu.com)
颖杏,不同的地方是坛芽,Hilt會(huì)通過APT對(duì)依賴注入的作用類生成一個(gè)“Hilt_類名.java”類,然后該作用類會(huì)繼承這個(gè)生成類获讳,然后通過字節(jié)碼插樁活喊,在生成類中添加以下方法,從而實(shí)現(xiàn)依賴的注入帅矗。
protected void inject() {
if (!injected) {
injected = true;
((FirstActivity_GeneratedInjector) this.generatedComponent()).injectFirstActivity(UnsafeCasts.<FirstActivity>unsafeCast(this));
}
}
而使用Dagger2的時(shí)候浑此,這一部分代碼需要自己手動(dòng)在作用類中添加滞详。
本文完整源碼公眾號(hào)【木水Code】回復(fù)“Hilt”即可獲取。
關(guān)注木水小站 (zhangmushui.cn)和微信公眾號(hào)【木水Code】蒲犬,及時(shí)獲取更多最新文章稀火。