Daggerを使ってDI

# はじめに
新卒で入社してから2ヶ月が立ちました。Androidに少しはなれてきたかな…
ということで今回は、Daggerを使ってDIしていきたいと思います！
[Dagger Hilt](https://aakira.app/blog/2020/05/dagger-hilt/)が、最近話題になってますね。
今後、Daggerにしろ、KoinにしろDIコンテナを使うことは必須だと思うので復習していきます！

※[前回](https://qiita.com/karass/items/a62d27a16b185abf47f0)の続きです



# Gradle
gradleにDaggerを追加します。

```build.gradle
    // Dagger
    def daggerVersion = '2.26'
    implementation "com.google.dagger:dagger:$daggerVersion"
    kapt "com.google.dagger:dagger-compiler:$daggerVersion"
```
# 実装
Daggerのオブジェクトグラフに、あるクラスのインスタンスを取得する方法を追加する必要があります。
`@Inject`アノテーションをつけることで、これを実現します。

今回、
ViewModelはRepositoryに依存していて、
RepositoryはDatabaseに依存しています。

## ViewModel
```MainViewModel.kt
class MainViewModel @Inject constructor(private val repository: TodoRepository) : ViewModel() {
    val todoList = repository.allTodoList

    fun insert(todo: Todo) = viewModelScope.launch {
        withContext(Dispatchers.IO){
            repository.insert(todo)
        }
    }
```

## Repository
```TodoRepository.kt
class TodoRepository @Inject constructor(private val todoDao: TodoDao) {
    val allTodoList = todoDao.getAll()

    @WorkerThread
    suspend fun insert(todo: Todo) {
        todoDao.insert(todo)
    }
}
```

`@Inject`アノテーションをつけることで、クラスのインスタンスの提供方法をDaggerに伝えることができました。

## Module
Interfaceなど、直接インスタンス化できないものの提供方法をDaggerに伝える必要があります。
依存関係の定義をグループ化するには、`@Module`アノテーションをつけます。

```DatabaseModule.kt
@Module
class DatabaseModule() {

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

    @Singleton
    @Provides
    fun provideTodoDao(todoDatabase: TodoDatabase) = todoDatabase.todoDao()
}
```

`@Module`アノテーションをつけたクラスに、インスタンスの生成方法を`@Provides`アノテーションで実現します。




## Component
ComponentはDaggerがオブジェクトグラフを生成して、あるクラスのインスタンスを取得する役割があります。
Componentを実装するには、`@Component`アノテーションをInterfaceにつけます。

```AppComponent.kt
@Singleton
@Component(
    modules = [
        DatabaseModule::class
    ]
)
Interface AppComponent {

    @Component.Factory
    interface Factory {
        fun create(@BindsInstance context: Context): AppComponent
    }
    fun mainViewModel(): MainViewModel
}
```

`@Singleton`アノテーションをつけることで、Singletonを実現します。
また、ComponentにModuleクラスで定義した依存関係を追加するために、`modules`パラメータに記述します。

`@Component.Factory`アノテーションでは、Componentのインスタンス取得時に特別な処理を定義することができます。今回は、Daggerのオブジェクトグラフ生成時にContextを渡したいので、引数に`@BindsInstance`アノテーションをつけます。

## Aplication
AppComponent.Factoryを使い、AppComponentのインスタンスを取得します。
インスタンス取得時にContextを渡します。

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

    override fun onCreate() {
        super.onCreate()
        component = DaggerAppComponent.factory().create(applicationContext)
    }
}
```

## Activity
```MainActivity.kt
class MainActivity : AppCompatActivity() {

    private val mainViewModel: MainViewModel by lazy {
        TodoApplication.component.mainViewModel()
    }
...
```
これでMainActivityにMainViewModelを提供することができました。

# おわりに
Todoアプリの削除機能を実装する前に、Daggerを使ってDIしてみました！
もし間違った記述があるなら、コメントで教えてほしいです!!!

Dagger Hiltも、時間があったら触ってみようかな。