【はじめてのHilt】Hilt + Room で依存関係注入してみた

#この記事について
MVVMでのAndroidのDIライブラリであるHiltの使い方を、同じJetpackライブラリであるRoomを用いて解説します。
今回はRoomの構築部分は割愛します。

#Hiltの依存関係を追加

まずは、Hiltプラグインをプロジェクトのルートに追加します。

```build.gradle
buildscript {
    ...
    dependencies {
        ...
        def hilt_version = '2.33-beta'
        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
    }
}
```

次に、**app/build.gradle**ファイルに依存関係を追加します。

```app/build.gradle
plugins {
    ...
    id 'kotlin-kapt'
    id 'dagger.hilt.android.plugin'
}

dependencies {
    def hilt_version = "2.33-beta"
    implementation "com.google.dagger:hilt-android:$hilt_version"
    kapt "com.google.dagger:hilt-android-compiler:$hilt_version"
}
```

Java8を有効にするには、同じく***app/build.gradle***に以下を追加

```app/build.gradle
android {
  ...
  compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}
```

#ApplicationクラスにHiltを導入

Applicationを継承した自作のApplicationクラスに**＠HiltAndroidApp**をつけます。

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

作成したMyApplicationを**AndroidManifest.xml**に追記します。

```xml:AndroidManifest.xml
<application
        android:name="(プロジェクト名).MyApplication"
```

これにより、HiltコンポーネントはApplication オブジェクトのライフサイクルにアタッチされ、依存関係を提供します。
Applicationはアプリの親コンポーネントであることから、他のコンポーネントが依存関係にアクセスできるようになります。

#Androidクラスに依存関係を注入する
Application クラスで Hilt がセットアップされ、アプリケーションレベルのコンポーネントが利用可能になると、**＠AndroidEntryPoint** アノテーションが付けられた他の Android クラスに依存関係を提供できるようになります。

```kotlin:MyActivity.kt
@AndroidEntryPoint
class MyActivity : AppCompatActivity() {...}
```
Fragmentを利用する際も同様に**＠AndroidEntryPoint**をつけます。

```kotlin:MyFragment.kt
@AndroidEntryPoint
class MyFragment : Fragment() {...}
```
**※Fragmentの親となるActivityにも＠AndroidEntryPointを設置することを忘れないように！！**

#Hiltを使ってViewModelオブジェクトを注入する
次に、ActivityやFragmentと紐づいているViewModelに依存関係を注入していきます。ViewModelには**＠HiltViewModel**をつけます。
また、このときにViewModelからRepositoryを参照・使用するために依存関係を注入していきますが、この方法としては**＠Inject**を使った以下の２つがあります。

**・Constructor Injection**
**・Field Injection**

以上２つの注入の仕方について説明します。

##Constructor Injection

```kotlin:MyViewModel.kt
@HiltViewModel
class MyViewModel @Inject constructor(
    private val repository: MyRepository
): ViewModel() {...}
```

本記事ではこの後、Constructor Injectionを使っていきます。

##Field Injection

```kotlin:MyViewModel.kt
@HiltViewModel
class MyViewModel(): ViewModel() {
    @Inject lateinit var repository: MyRepository
}
```

#RepositoryにRoom Daoを注入
続いてRepositoryをみていきましょう。
ここではRoomのDaoをRepositoryに注入し、Daoにあるメソッドを呼び出します。注入の仕方は前述のViewModelと同じ**＠Inject**で注入できます。

```kotlin:MyRepository.kt
class MyRepository @Inject constructor(private val myDao: MyDao) {...}
```

これでRepositoryからMyDaoを呼び出すことが可能になります。
例えばMyDao内でSELECTしてきた次のようなデータを

```kotlin:MyDao.kt
@Dao
interface MyDao {
    @Query("SELECT * FROM user")
    fun findAll(): List<User>
}
```

Repositoryからは

```kotlin:MyRepository.kt
class MyRepository @Inject constructor(private val myDao: MyDao) {
    fun findAllInDB() = myDao.findAll()
}
```

これで呼び出し完了です！！

##Hiltモジュールの作成

Hiltモジュールでは**＠Module**をつけたクラスから、特定の型のインスタンスの提供方法を Hilt に知らせることができます。
ここではRoom　Databaseの構築と、Daoの実装を行います。

```kotlin:MyModule.kt
@Module
@InstallIn(SingletonComponent::class)
object MyModule {

    @Singleton
    @Provides
    fun provideDatabase(
        @ApplicationContext context: Context
    ) = Room.databaseBuilder(context, AppDatabase::class.java, "user_db").build()

    @Singleton
    @Provides
    fun provideDao(db: AppDatabase) = db.myDao()
}
```

**・＠InstallIn**：各モジュールが使用またはインストールされる Android クラスを知らせます。ここでは**SingletonComponent**を用いることで、アプリケーション内のどこからでもアクセス可能になります。その他のComponentについては[Android Developers](https://developer.android.com/training/dependency-injection/hilt-android#generated-components)をご覧ください。

**・＠Singleton**：同じインスタンスを使いまわすことができます。このアノテーションを外すと、依存注入のたびに新しいインスタンスが生成されます。

**・＠Provides**：このアノテーションをつけた関数のインスタンスを提供します。Room等のDBのほか、RetrofitやOkHttpClientのBuildでインスタンスを生成するときも同様です。


とりあえずはこれでHiltを使ったRoomの依存関係注入は完了です！
同じようにHilt + Roomを使ったアプリをGitHubで公開しているので、こちらもご覧ください。
[GitHub](https://github.com/k-yamamoto1208/android_meditation)

#参考記事
[Hilt and Jetpack integrations](https://developer.android.com/training/dependency-injection/hilt-jetpack)
[Dependency injection with Hilt](https://developer.android.com/training/dependency-injection/hilt-android#inject-provides)
[How to create and use a Room Database in Kotlin [Dagger-Hilt]
](https://stackoverflow.com/questions/63146318/how-to-create-and-use-a-room-database-in-kotlin-dagger-hilt)