---
# System prepended metadata

title: Ｈilt 快速使用筆記 - 基本
tags: [Tag(Android 技術相關)]

---

# Ｈilt 快速使用筆記 - 基本

[TOC]

![Dependency injection - Hilt ](https://hackmd.io/_uploads/S1rP0WWO0.png)


## Gradle 設定

1. Hilt 使用 [Java 8 功能](https://developer.android.com/studio/write/java8-support?hl=zh-cn) 以上
2. project/ **build.gradle**
    1. `plugins`
3. **app/build.gradle**
    1. 啟用允許引用產生的程式碼 `correctErrorTypes true` 
    2. `dependencies` 

## 基本常用 Annotation Type

### `@HiltAndroidApp`

1. 必須設定在繼承`Application()`的類別上
2. 觸發代碼生成的操作，包含提供 application-level dependency 容器
3. 產生的Hilt元件附加到Application物件的生命週期並提供依賴項目

```kotlin
@HiltAndroidApp
class ExampleApplication : Application() { ... }
```

### `@AndroidEntryProint`

1. Application class 有設定`@HiltAndroidApp`，設定Annotation可以將相依性注入 Android class 
2. Hilt的入口點

```kotlin
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() { ... }
```

### **`@Inject`**

1. 宣告注入的依賴物件，設定private的會導致編譯錯誤
2. 需相應**`@Inject`**要注入的物件

```kotlin
@AndroidEntryPoint
class ExampleActivity : AppCompatActivity() {

  @Inject lateinit var analytics: AnalyticsAdapter
  ...
}
```

```kotlin
class AnalyticsAdapter @Inject constructor(
  private val service: AnalyticsService
) { ... }
```

## 不能透過構造函數注入型別

> cannot be constructor-injected a type，Hilt can provide with binding information by using Hilt modules
> 

Hilt modules 要annotated with`＠Module`、`@InstallIn`

1. interface → `@Binds`
2. external library  → `@Provide`
3. `@Binds` vs `@Provide`

### `@Module`

- 告訴Hilt 知道如何提供某些類型的實例

### `@InstallIn`

- 有**`@Module` 類別以**`@InstallIn`告訴 Hilt 每個模組將在哪個 Android 類別中關聯的所有產生的元件中使用和安裝
- Android 類別中關聯元件:`ActivityComponent::class`、`SingletonComponent::class`

### `@Binds`

- 告訴 Hilt 在需要提供**介面實例**時要使用`@Inject` constructor
- `＠Binds` function 參數告訴 Hilt 提供哪個實作
- `＠Binds` function 回類型告訴 Hilt 該函數提供哪個介面的實例

```kotlin
interface AnalyticsService {
  fun analyticsMethods()
}

// 實作介面
class AnalyticsServiceImpl @Inject constructor(
  ...
) : AnalyticsService { ... }

@Module
@InstallIn(ActivityComponent::class)
abstract class AnalyticsModule {

  @Binds  
  abstract fun bindAnalyticsService(
    analyticsServiceImpl: AnalyticsServiceImpl 
  ): AnalyticsService 
}
```

### `@Provide`

1. 外部套件 like [Retrofit](https://square.github.io/retrofit/), [`OkHttpClient`](https://square.github.io/okhttp/), or [Room databases](https://developer.android.com/topic/libraries/architecture/room)、或是設計模式之一的 [builder pattern](https://en.wikipedia.org/wiki/Builder_pattern).
2. `＠Provides` function
3. `＠Provides` function 回類型告訴 Hilt 提供的實例

```kotlin
@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    // Potential dependencies of this type
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .build()
               .create(AnalyticsService::class.java)
  }
}
```

## **Provide multiple bindings for the same type**

### `@qualifiers`

- 自定義 annotate class 用於 @Binds 或 @Provides 方法的，
- 類別前加上`@Qualifer`、`@Retention(AnnotationRetention.BINARY)`

1. **範例 `@Provides`** 
    - Hilt 模組與`@Provides` 兩種方法具有相同的傳回類型，但`@Qualifer`定義的annotate將它們標記為兩個不同的綁定
    - 更換自定義Annoctation

```kotlin
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class AuthInterceptorOkHttpClient

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class OtherInterceptorOkHttpClient
```

```kotlin
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {

  @AuthInterceptorOkHttpClient
  @Provides
  fun provideAuthInterceptorOkHttpClient(
    authInterceptor: AuthInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(authInterceptor)
               .build()
  }

  @OtherInterceptorOkHttpClient
  @Provides
  fun provideOtherInterceptorOkHttpClient(
    otherInterceptor: OtherInterceptor
  ): OkHttpClient {
      return OkHttpClient.Builder()
               .addInterceptor(otherInterceptor)
               .build()
  }
}

@Module
@InstallIn(ActivityComponent::class)
object AnalyticsModule {

  @Provides
  fun provideAnalyticsService(
    @AuthInterceptorOkHttpClient okHttpClient: OkHttpClient
  ): AnalyticsService {
      return Retrofit.Builder()
               .baseUrl("https://example.com")
               .client(okHttpClient)
               .build()
               .create(AnalyticsService::class.java)
  }
}

// As a dependency of a constructor-injected class.
class ExampleServiceImpl @Inject constructor(
  @AuthInterceptorOkHttpClient private val okHttpClient: OkHttpClient
) : ...

// At field injection.
@AndroidEntryPoint
class ExampleActivity: AppCompatActivity() {

  @AuthInterceptorOkHttpClient
  @Inject lateinit var okHttpClient: OkHttpClient
}
```

2. 範例 `@Binds`
    - class 取得 `@Inject` 建構子的參數在更換自定義Annoctation `@BindElectricEngine`

```kotlin
@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindElectricEngine

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class BindHybridEngine
```

```kotlin
@Module
@InstallIn(ActivityComponent::class)
abstract class EngineModule {  
	
		@BindElectricEngine
	  @Binds
	  abstract fun bindElecEngine(engine: ElectricEngine):Engine  
		
		@BindHybridEngine
	  @Binds
	  abstract fun bindHybridEngine(engine: HybridEngine):Engine

}

class Car @Inject constructor(
  @BindElectricEngine private val engine: Engine
) {
    fun start(){
        engine.start()
    }
}
```

# 參考網址
1. [將 Dagger 應用程式遷移到 Hilt](https://developer.android.com/codelabs/android-dagger-to-hilt?hl=zh-cn)
2. [Dependency injection with Hilt ](https://developer.android.com/training/dependency-injection/hilt-android?hl=zh-cn)
3. [Android的依賴注入－Hilt函式庫](https://jimmy4302001.medium.com/android%E7%9A%84%E4%BE%9D%E8%B3%B4%E6%B3%A8%E5%85%A5-hilt%E5%87%BD%E5%BC%8F%E5%BA%AB-2514c1f2fa65)