Hiltを使ってみよう

今回の記事は[レコチョク Advent Calendar 2021](https://qiita.com/advent-calendar/2021/recochoku)の7日目の記事となります。

# はじめに

はじめまして！株式会社レコチョクでAndroid開発を担当しています、入社2年目の杉山です！
音楽が好きで普段からよくライブに行っています。特にアイドルが好きでメジャーアイドルからインディーズアイドルまで様々なグループを見たりしています！

そんな僕からはAndroid開発に参加するようになって触れたDIライブラリの**Hilt**について記事をまとめたいと思います！

# Hiltって、DIって何？
そもそもHiltってなんぞやって話になりますが、HiltはAndroid用の依存関係をインジェクションするライブラリになります。いわゆるDIライブラリと呼ばれるものです。
## DIって？
ある程度の規模のプロジェクトになると、「あるクラスAの実装を行う際、他のクラスBのオブジェクトが必要」という場面に遭遇することが増えます。この関係を**依存関係**と呼びます。
するとAの内部でBを呼び出す必要が出てきます。すると関係は固定的になりAがBを利用していることが外部からわかりにくくなります。

これを解消するために依存性注入（Dependency Injection）いわゆるDIと呼ばれるものが必要になります。その場合、Aの内部にBを直接記述せず、メソッドの引数などの形で受け取って呼び出す形にします。これにより、AとBの依存関係は外部から任意に指定、変更することができるようになり、例えばBと同じインターフェースを実装したCを与えたり、Bをモックとして与えてAのみを対象とした単体テストができるようになったりします。

## Hiltとは
Daggerの上に構築された新しい依存性注入ライブラリであり、Androidアプリでの仕様を簡素化してくれるものになります。
Daggerとはオブジェクト間の依存関係を管理するコードを自動生成してくれるツールになります。
アノテーションを使用して、クラスの依存関係を宣言し、依存関係を満たす方法を指定していれば、ビルド時に自動的に依存関係を管理してくれます。HiltはDaggerを元に更に簡素化して使用できるようにしたものになります。実際には、オブジェクトの作成方法とオブジェクトを挿入する場所を定義するだけで使用することができるようになっています。
プロジェクト内のすべてのAndroidクラスにコンテナを提供し、そのライフサイクルを自動で管理することで、アプリケーションでDIを行うための標準的な方法を提供してくれます。([公式ドキュメント](https://developer.android.com/training/dependency-injection/hilt-android?hl=ja)より)
今回はそのHiltに関して導入と実際に使ってみた部分に関してまとめていきたいと思います！

# Hiltを導入
Hiltを使用するにあたって、まずGradleに必要なプラグインを追加します。
* ルート直下のGradle

```
buildscript {
    dependencies {
        classpath("com.google.dagger:hilt-android-gradle-plugin:2.40.2")
    }
}
```

* appフォルダ配下のGradle

```
plugins {
    id('dagger.hilt.android.plugin')
}
dependencies {
    implementation("com.google.dagger:hilt-android:2.40.2")
    kapt("com.google.dagger:hilt-android-compiler:2.40.2")
}
```

これで導入は完了です。実際に使ってみます！今回はToDoアプリのタスク管理する部分に導入しようと思います
Hiltを使用するアプリケーションには次のようなアノテーションを付与します。

```
@HiltAndroidApp
class ToDoApplication: Application() {}
```

これでこのアプリケーションではHiltを使用することを宣言できました。
アプリケーションクラスはAndroidManifestで指定します

```
…
    <application
        android:name=".ToDoApplication"
…

```

Hiltを対応させるアクティビティとフラグメントに対しては次のようなアノテーションを付与します。

```
@AndroidEntryPoint
class AddEditToDoActivity : AppCompatActivity() {
```

フラグメントのみ付与してアクティビティに付与しないとエラーが出てしまうので注意です！

ここまで出来たらHiltのモジュールを作成します。

```
@Module
@InstallIn(SingletonComponent::class)
object ToDoModule {
    @Provides
    @Singleton
    fun provideToDoDatabase(
        @ApplicationContext context: Context
    ): ToDoDataBase {
        return ToDoDataBase.getInstance(context)
    }
}
```

まずは`@Module`と`@InstallIn()`を付与します。`@Module`でHiltモジュールにします。`@InstallIn()`でModuleをどのHiltコンポーネントにインストールするかを指定します。各メソッドには`@Provides`を付与し、一つだけ作成するようにする(アプリ内で共通の一つ)にする場合は`@Singleton`を付与します。

Contextを定義に使用する場合は`@ApplicationContext`を利用することで定義が可能になります。

ビューモデルをHilt対応したものに修正します。

```
@HiltViewModel
class AddEditToDoViewModel @Inject constructor(
    private val toDoRepository: ToDoRepository
): ViewModel() {
```

このとき`@Inject`というアノテーションを使用しています。それによりHiltが自動的に対象インターフェースの実装クラスをDIしてくれます。

ビューモデルをフラグメントに持たせる場合以下のように宣言します。

```
@AndroidEntryPoint
class AddEditToDoFragment : Fragment() {
    private val addEditToDoViewModel: AddEditToDoViewModel by viewModels()
```


今回は以上によりデータベース周りの依存関係をHilt対応させることが出来ました。

# まとめ
今回はHiltを業務で使ってみたので、Hiltの初歩的な内容についてまとめてみました。
実際に業務で使っていると、クラス間の関係性がわかりやすくなり、テストがしやすいというメリットがあったので今後も使っていきたいと思います！


明日の[レコチョク Advent Calendar 2021](https://qiita.com/advent-calendar/2021/recochoku)は8日目 デザイナーとスクラムです。お楽しみに！

この記事はレコチョクのエンジニアブログの記事を転載したものとなります。

https://techblog.recochoku.jp/7924