Hilt入門

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. Android 應用的應用圖表模型

各個類之間的依賴關系可以表示為圖表,其中每個類都連接到其所依賴的類。所有類及其依賴關系的表示法便構成了應用圖表。在圖 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

最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容