Dagger Hilt触ってみた

# はじめに
巷で噂のDagger Hiltをようやく触ってみました。[Codelab](https://codelabs.developers.google.com/codelabs/android-dagger-to-hilt/#0)を一通り終わったので、実際に[過去の記事](https://qiita.com/karass/items/883353b80ac84becf44c)でDaggerを使ってDIしたのですがそれをHiltに移行した手順をまとめます。

# Gradle
```build.gradle
    // build.gradle (Project)
    ext.hilt_version = '2.28-alpha'
    dependencies {
        classpath "com.google.dagger:hilt-android-gradle-plugin:$hilt_version"
    }

```

```build.gradle
    // build.gradle (App)
    // Dagger_hilt
    implementation "com.google.dagger:hilt-android:$hilt_version" // 必須
    kapt "com.google.dagger:hilt-android-compiler:$hilt_version" // 必須

    def dagger_hilt_view_model_version = "1.0.0-alpha01"
    implementation "androidx.hilt:hilt-lifecycle-viewmodel:${dagger_hilt_view_model_version}"
    kapt "androidx.hilt:hilt-compiler:${dagger_hilt_view_model_version}"
```
今回は、ViewModelを使うので、`hilt-compiler`と`hilt-lifecycle-viewmodel`を追加した。

# 実装
移行の順番は、
1. Application & @Singleton
2. Fragment & Activity

ということで、Applicationを見てみましょう。
## Application
Hiltに移行する前のコードがこちらです。`Application`では、独自に設計した`Component`をインスタンス化していました。しかし、Hiltでは標準のComponentが用意されていてComponentを定義する必要がなくなったらしい。

```TodoApplication.kt
class TodoApplication : Application() {
    companion object {
        lateinit var component: AppComponent private set
    }

    override fun onCreate() {
        super.onCreate()
        component = DaggerAppComponent.factory().create(applicationContext)
    }
}
```
Hiltでは`Application`を`@HiltAndroidApp`アノテーションをつけて定義します。

```TodoApplication.kt
@HiltAndroidApp
class TodoApplication : Application() {
//    companion object {
//        lateinit var component: AppComponent private set
//    }
//
//    override fun onCreate() {
//        super.onCreate()
//        component = DaggerAppComponent.factory().create(applicationContext)
//    }
}
```
このコードからわかるように`Component`自体もいらないので、`AppComponent`を削除します。

```AppComponent.kt
//@Singleton
//@Component(
//    modules = [
//        DatabaseModule::class
//    ]
//)
//interface AppComponent {
//
//    @Component.Factory
//    interface Factory {
//        fun create(@BindsInstance context: Context): AppComponent
//    }
//    fun mainViewModel(): MainViewModel
//}
```

## Activity
元々あった`Component`を削除したので、ActivityやFragmentにInjectできるように、`@AndroidEntryPoint`アノテーションを記述しなければならない。

```MainActivity.kt
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
```
今回は、Fragmentが登場しませんが、もしFragmentにInjectしたいときはそれを所持するActivityにも`@AndroidEntryPoint`を付ける必要があります。

## Module
Moduleの定義方法は、`@InstallIn(ApplicationComponent::class)`アノテーションをつける必要があります。`@InstallIn`アノテーションでHiltが生成するComponentにModuleを紐付けます。

```DatabaseModule.kt
@InstallIn(ApplicationComponent::class)
@Module
class DatabaseModule() {


    @Singleton
    @Provides
    fun provideTodoDatabase(@ApplicationContext context: Context) =
        Room.databaseBuilder(context,
            TodoDatabase::class.java,
            "database_name")
            .build()

    @Singleton
    @Provides
    fun provideTodoDao(todoDatabase: TodoDatabase) = todoDatabase.todoDao()
}
```
移行前は、`Context`をComponentのインスタンス生成する時に渡していたがそれをする必要がなくなりました。 すでにBinding済みのContextを使用することができます。`@ApplicationContext`か`@ActivityContext`をつけるだけで使用できます。
## ViewModel
ViewModelをHiltを使ってDIする場合、constructorに`@ViewModelInject`アノテーションをつけます。

```MainViewModel.kt
class MainViewModel @ViewModelInject constructor(private val repository: TodoRepository) : ViewModel() {
```
最後Activityに、

```MainActivity.kt
private val mainViewModel: MainViewModel by viewModels()
```
を記述すれば移行完了です。