【Kotlin/Android】Hiltの導入方法と使い方!依存性注入(DI)とは?

この記事からわかること
- Android Studio/KotlinでHiltの使い方
- DI(依存性注入)とは?
- 導入方法と仕組み
index
[open]
\ アプリをリリースしました /
環境
- Android Studio:Meerkat
- Kotlin:2.0.21
- Hilt:2.56.2
Hiltとは?
「Hilt」とはAndroidアプリ開発においてオブジェクト同士の依存関係を解決し、プロジェクト内のオブジェクトに対して依存性注入(DI)デザインパターンを活用するためのライブラリです。Googleが管理するライブラリで内部的にはDaggerというライブラリを使っており、学習コストが高いDaggerをラップして使いやすくしてあるのがHiltになります。
依存関係とは?
そもそも依存関係とはオブジェクト同士が依存している関係のことです。ここでいうオブジェクトはクラスや構造体、メソッドなども当てはまります。例えば以下はUserクラスがActionGameクラスに依存している関係になります。
オブジェクト同士の依存関係やDIについての詳細は以下の記事を参考にしてください。
導入方法と前準備
公式リファレンス:Dependency injection with Hilt
Hiltを導入するためにはプロジェクトの「build.gradle」にkspとhiltの依存関係を追加します。
続いてモジュール側の「build.gradle」にもkspとhiltの依存関係を追加します。
これで依存関係の設定は完了です。次にプロジェクト内でHiltを利用できるようにしていきます。
Hiltを利用できるようにするために@HiltAndroidApp
アノテーションが付与されたApplication
クラスを実装する必要があります。Application
を継承したクラスを実装済みであれば@HiltAndroidApp
アノテーションを付与し、なければ新規で継承したクラスを空でも良いので定義しておいてください。
Application
サブクラスを定義したら忘れずに「AndroidManifest.xml」ファイルに追加しておいてください。
Hiltを使用した実装例
Androidで依存関係インジェクションを行う主な方法は2つあります。
- コンストラクタインジェクション:ViewModel、Repository...
- フィールドインジェクション(セッターインジェクション):Activity、Fragment...
コンストラクタインジェクション
コンストラクタインジェクションはその名前の通りコンストラクタを使用して依存性を挿入する方法です。ViewModelやRepositoryなどシンプルな独自のクラスなどでは簡単にコンストラクタインジェクションを実装することができます。
フィールドインジェクション(セッターインジェクション)
ActivityやFragmentなどシステムによってインスタンス化されるクラスはコンストラクタインジェクションが不可能です。そのためクラスの作成後に依存関係がインスタンス化されます。
公式リファレンス:Android での依存関係インジェクション
コンストラクタインジェクション
例えばViewModelやRepositoryなど依存性注入(DI)を行うためには「コンストラクタインジェクション」という方法を用います。最初にRepositoryクラスのconstructor
に対して@Inject
アノテーションを付与します。引数でContext
を受け取りたい場合などは@ApplicationContext
を付与してあげてください。
続いてViewModel側に@HiltViewModel
アノテーションを付与し、こちらもconstructor
に対して@Inject
アノテーションを付与します。またViewModelはandroidx.lifecycle.ViewModel
を継承させておきます。
おすすめ記事:【Kotlin/Android Studio】ViewModelの使い方!画面再構築のデータ保持
最後にViewModelの呼び出し側(Activity)に@AndroidEntryPoint
を付与します。ViewModelのインスタンス化はviewModels()
を使用します。
これでコンストラクタインジェクションの実装は完了です。
フィールドインジェクション
コンストラクタを経由できないActivityやFragmentに依存性注入(DI)を行うためには「フィールドインジェクション」という方法を使用します。Repositoryの記載は先ほどと変わらずActivity側で@Inject
アノテーションを付与するのがlateinit
で定義した変数になります。
おすすめ記事:【Kotlin/Android】lateinit(遅延初期化プロパティ)とは?使い方
lateinit
を使用しているのでsuper.onCreate
が実行された後でないと参照できないので注意してください。
@ActivityContextと@ApplicationContext
Contextを注入するためのアノテーションとして@ActivityContext
と@ApplicationContext
があります。両者の違いは「アプリ全体に依存したContext」か「Activityに依存したContext」かという違いです。
アノテーション | 概要 | 使用用途 |
---|---|---|
@ActivityContext | Activityに依存したContext | DB操作, DIのModule, Repositoryなど |
@ApplicationContext | アプリ全体に依存したContext | Dialog, Toast, View関連のUI操作など |
UIに絡む部分には@ActivityContext
を使ってあげる必要がありますが、適切に解放しないとメモリリークを引き起こすので注意してください。
インターフェースで抽象度をあげる:@Module / @Provides
先ほどのRootRepository
を共通のインターフェースを定義して継承させ、モックなどに切り替えやすくテストしやすい設計にしたいと思います。その場合先ほどのコンストラクタインジェクションのままだと期待通りに実装できないので@Module
と@Provides
アノテーションを使用していきます。
まずはRootRepository
のインターフェースを定義します。RootRepository
と言う名前はインターフェースで使用したいので元のクラスはRootRepositoryImpl
へ変更します。
RootRepositoryImpl
はRootRepository
を継承させるくらいで特に変化はありません。
肝となるのがRepositoryModule
クラスです。このモジュールクラスが実際に注入する依存関係を定義するクラスになっています。@Module
アノテーションを付与して依存性提供の定義をする場所であることを示し、@Provides
で対象のインターフェースにどの実態を渡すかを定義します。
まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。