Kotlin + Android + ViewModelだってDIしたい！！！

# 概要
Android超絶初心者の僕がkotlinでViewModelをDIするときに苦戦したのでメモ程度にViewModelをDIする方法を書きます。

## 全体設計
今回作っていたのでTodoリストのようなもので
<img width="805" alt="スクリーンショット 2020-05-28 18.00.37.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/83409/dcb86c91-1b26-0988-7715-f49a1c15e685.png">
めちゃくちゃざっくりした設計はこんな感じです。


## 今回やりたかったこと
TodoViewModelからFirestoreRepositoryをDIしたかった。

## 普段のDI
firestoreRepositoryからFirebaseFirestoreをDIするときは

```kotlin
class FirestoreRepository(val db: FirebaseFirestore = FirebaseFirestore.getInstance()) {
```

こんな感じでかけていたので特に苦戦することはなかったのですが....

## 詰まった点

同じようにTodoViewModelの方で

```kotlin
class TodoViewModel(
    application: Application,
    private val firestoreRepository: FirestoreRepository = FirestoreRepository()
) : AndroidViewModel(application) {
```

こんな感じで書いた所、実行時に

```
 Process: com.example.myapplication, PID: 12747
    java.lang.RuntimeException: Cannot create an instance of class com.example.myapplication.TodoViewModel
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:269)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185)
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
        at com.example.myapplication.fragment.IndexFragment.onCreateView(IndexFragment.kt:31)
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698)
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:310)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1185)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354)
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432)
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495)
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447)
        at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167)
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990)
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945)
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847)
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413)
        at android.os.Handler.handleCallback(Handler.java:883)
        at android.os.Handler.dispatchMessage(Handler.java:100)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
     Caused by: java.lang.NoSuchMethodException: com.example.myapplication.TodoViewModel.<init> [class android.app.Application]
        at java.lang.Class.getConstructor0(Class.java:2332)
        at java.lang.Class.getConstructor(Class.java:1728)
        at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)
        at androidx.lifecycle.SavedStateViewModelFactory.create(SavedStateViewModelFactory.java:106) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:185) 
        at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150) 
        at com.example.myapplication.fragment.IndexFragment.onCreateView(IndexFragment.kt:31) 
        at androidx.fragment.app.Fragment.performCreateView(Fragment.java:2698) 
        at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:310) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1185) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1354) 
        at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1432) 
        at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1495) 
        at androidx.fragment.app.BackStackRecord.executeOps(BackStackRecord.java:447) 
        at androidx.fragment.app.FragmentManager.executeOps(FragmentManager.java:2167) 
        at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1990) 
        at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1945) 
        at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1847) 
        at androidx.fragment.app.FragmentManager$4.run(FragmentManager.java:413) 
        at android.os.Handler.handleCallback(Handler.java:883) 
        at android.os.Handler.dispatchMessage(Handler.java:100) 
        at android.os.Looper.loop(Looper.java:214) 
        at android.app.ActivityThread.main(ActivityThread.java:7356) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) 
```

このようなエラーが吐かれてしまった...

## 解決策
Factoryクラスなるものを作ればいけるとのこと。
基本的にここに書かれてるんですけど、Javaなんですよね...
https://stackoverflow.com/questions/46283981/android-viewmodel-additional-arguments

kotlinバージョンだと

Factoryクラスは

```kotlin
package com.example.myapplication

import android.app.Application
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider

class TodoViewModelFactory(
    private var application: Application
) : ViewModelProvider.Factory {

    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return TodoViewModel(application) as T
    }
}
```
こんな感じで、呼び出し側は

```kotlin
viewModel = ViewModelProvider(
            requireActivity(),
            TodoViewModelFactory(mainActivity.application)
        ).get(TodoViewModel::class.java)
```

こんな感じになるかと

解決。
Dagger？とか使えばこれも簡単らしい...？？？