Architecture Components を Dagger2 と併用する際の ViewModelProvider.Factory について

# はじめに

こちらは以下のスライドの前半部分の補足記事となっています。
スライドについても合わせて見ていただければ幸いです。

Kotlin × Architecture Components 実践
https://speakerdeck.com/satorufujiwara/kotlin-x-architecture-components

これまでArchitecture ComponentsとDagger2を組み合わせた実装については、以下のような記事で紹介してきました。
本記事はその中の`ViewModelProvider.Factory`にフォーカスした記事です。

- [Kotlin + Architecture Component + Dagger2によるAndroidアプリ設計](https://qiita.com/satorufujiwara/items/0f95ccfc3820d3ee1370)
- [Architecture Components + Flux (+ Kotlin)によるAndroidアプリ設計](https://qiita.com/satorufujiwara/items/dfc55fc2e0316ae5d8fe)

Dagger2の導入やDagger2以外の実装についてはそれぞれの記事をご覧ください。

また、この記事は以下のバージョンのArchitecture Componentsを用いて書かれています。

```build.gradle
implementation "android.arch.lifecycle:runtime:1.0.3"
implementation "android.arch.lifecycle:extensions:1.0.0"
kapt "android.arch.lifecycle:compiler:1.0.0"
```

# 参考リポジトリ


- https://github.com/googlesamples/android-architecture-components/tree/master/GithubBrowserSample
 - GoogleによるDagger2を使ったサンプル(Java)、すべての参考元
- https://github.com/googlesamples/android-architecture/tree/todo-mvvm-live
 - Dagger2を使わずに`ViewModelProvider.Factory`を自前で作るサンプル
- https://github.com/satorufujiwara/kotlin-architecture-components
 - Dagger2のSubComponentを使ったサンプル
- https://github.com/satorufujiwara/android-flux-architecture/tree/master/flux-arch
 - Dagger2のSubComponentを使った上、ViewModel以外のクラスを`PerActivityScope`を使ってInjectするサンプル 
- https://github.com/satoshun-example/DaggerArchitectureComponent
 - `ViewModel`クラスもDagger2を用いてinjectするサンプル

# Architecture ComponentsとDagger2を組み合わせる理由

まずはArchitecture ComponentsとDagger2を併用する理由と、その際に理解しておきたい部分について解説します。

## ViewModelのインスタンスはViewModelProvider経由で取得する

```kotlin
class MainViewModel : ViewModel()
```
上記のような`ViewModel`を継承した`MainViewModel`というクラスがある場合、このクラスのインスタンスを取得する際は以下のようにします。

```kotlin:MainActivity.kt
val viewModelProvider: ViewModelProvider = ViewModelProviders.of(this)
//ViewModelを継承したクラスを指定する
val viewModel: MainViewModel = viewModelProvider.get(MainViewModel::class.java)
```

この際、**`ViewModelProviders::of`から取得した`ViewModelProvider`クラスの関数`get`からインスタンスを取得する**必要があります。
上記はActivity内の例でしたが、Fragment内で取得する場合は以下のような挙動になります。

```kotlin:MainFragment.kt
viewModelA = ViewModelProviders.of(activity!!).get(MainViewModel::class.java)
// viewModelAとは別のインスタンス
viewModelB = ViewModelProviders.of(this).get(MainViewModel::class.java)
```

`viewModelA`と`viewModelB`は同じ型のクラスですが別のインスタンスです。
`ViewModelProviders::of`に指定できる引数は`FragmentActivity`もしくは`Fragment`ですが、それぞれの場合において内部的には以下のような処理が呼ばれています。

```java:ViewModelProviders.java
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    initializeFactoryIfNeeded(checkApplication(activity));
    return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}

public static ViewModelProvider of(@NonNull Fragment fragment) {
    initializeFactoryIfNeeded(checkApplication(checkActivity(fragment)));
    return new ViewModelProvider(ViewModelStores.of(fragment), sDefaultFactory);
}
```

`ViewModelStores`の中はさらに以下のようになっていて、

```java:ViewModelStores.java
public static ViewModelStore of(@NonNull FragmentActivity activity) {
    return holderFragmentFor(activity).getViewModelStore();
}

public static ViewModelStore of(@NonNull Fragment fragment) {
    return holderFragmentFor(fragment).getViewModelStore();
}
```

`holderFragmentFor`関数は以下のような`HolderFragment`内のstatic関数です。

```java:HolderFragment.java
public static HolderFragment holderFragmentFor(FragmentActivity activi
    return sHolderFragmentManager.holderFragmentFor(activity);
}

public static HolderFragment holderFragmentFor(Fragment fragment) {
    return sHolderFragmentManager.holderFragmentFor(fragment);
}
```

さらに辿ることで`HolderFragment.HolderFragmentManager`クラスに行き着きます。
このクラス内の`holderFragmentFor`関数がそれぞれ呼ばれています。

```java:HolderFragment.HolderFragmentManager
private static HolderFragment createHolderFragment(FragmentManager fragmentManager) {
    HolderFragment holder = new HolderFragment();
    fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss();
    return holder;
}

HolderFragment holderFragmentFor(FragmentActivity activity) {
    FragmentManager fm = activity.getSupportFragmentManager();
    HolderFragment holder = findHolderFragment(fm);
    if (holder != null) {
        return holder;
    }
    holder = mNotCommittedActivityHolders.get(activity);
    if (holder != null) {
        return holder;
    }
    if (!mActivityCallbacksIsAdded) {
        mActivityCallbacksIsAdded = true;
        activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
    }
    holder = createHolderFragment(fm);
    mNotCommittedActivityHolders.put(activity, holder);
    return holder;
}

HolderFragment holderFragmentFor(Fragment parentFragment) {
    FragmentManager fm = parentFragment.getChildFragmentManager();
    HolderFragment holder = findHolderFragment(fm);
    if (holder != null) {
        return holder;
    }
    holder = mNotCommittedFragmentHolders.get(parentFragment);
    if (holder != null) {
        return holder;
    }
    parentFragment.getFragmentManager()
            .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
    holder = createHolderFragment(fm);
    mNotCommittedFragmentHolders.put(parentFragment, holder);
    return holder;
```

このコードで注目したいのは、`FragmentActivity`の場合は`activity.getSupportFragmentManager()`が呼ばれ、`Fragment`の場合は`parentFragment.getChildFragmentManager()`が呼ばれているという箇所です。
それぞれの関数からは異なる`FragmentManager`が取得されるので、それぞの場合において、`findHolderFragment(fm)`で取得できる`HolderFragment`のインスタンスや、`createHolderFragment(fm)`で生成される`HolderFragment`のインスタンスは異なってきます。
すなわち**`ViewModelProviders::of`の引数(`FragmentActivity`or`Fragment`)から取得できる`FragmentManager`が同一かによって`HolderFragment`のインスタンスが同一がどうかが決まります**。

`HolderFragment`は`ViewModelStore`型のメンバ変数`mViewModelStore`を持っていて、`ViewModelStore`は`HashMap<String, ViewModel>`型のメンバ変数を用いて`ViewModel`のインスタンスを管理しています。
この`HashMap`型の変数の`String`型のキーは以下のように決められています。

```java:ViewModelProviders.java
public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
    String canonicalName = modelClass.getCanonicalName();
    if (canonicalName == null) {
        throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
    }
    return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
}
```

キーは`ViewModelProvider::get`の引数に指定したクラス名で決まるので、`HolderFragment`のインスタンスが同一であり、かつ、`ViewModelProvider:get`の引数に同一のクラス名を指定すれば`ViewModel`のインスタンスも同じになります。

まとめると、

```kotlin
val viewModel = ViewModelProviders.of(activity!!).get(MainViewModel::class.java)
```
上記のように`ViewModel`のインスタンスを取得する場合、

- `ViewModelProviders::of`の引数から取得できる`FragmentManager`が同一であれば、`ViewModel`のインスタンスの格納場所(`ViewModelStore`)が同一になる
- すなわち、異なるFragment同士であっても同じActivity内にあって、`ViewModelProviders::of`の引数にActivityを指定すれば同じ格納場所を取得できる
- 格納場所から`ViewModel`を取得する際、`ViewModelProvider:get`の引数のクラス名がそのキーとなる

## ViewModelProvider.Factoryを指定したViewModelのインスタンスの取得

先程の例だと`ViewModelProviders::of`の引数は1つしか指定しませんでしたが、この場合、内部的には以下のようになっています。

```java:ViewModelProviders.java
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    initializeFactoryIfNeeded(checkApplication(activity));
    return new ViewModelProvider(ViewModelStores.of(activity), sDefaultFactory);
}
```
`sDefaultFactory`というのは`ViewModelProvider.Factory`を継承したクラスで、以下のような実装になっています。

```java:DefaultFactory
public static class DefaultFactory extends ViewModelProvider.NewInstanceFactory {
    private Application mApplication;
    /**
     * Creates a {@code DefaultFactory}
     *
     * @param application an application to pass in {@link AndroidViewModel}
     */
    public DefaultFactory(@NonNull Application application) {
        mApplication = application;
    }
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
            //noinspection TryWithIdenticalCatches
            try {
                return modelClass.getConstructor(Application.class).newInstance(mApplication);
            } catch (NoSuchMethodException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (InstantiationException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }
        return super.create(modelClass);
    }
}
```

このクラスの親となっている`ViewModelProvider.NewInstanceFactory`は以下のようなクラスです。

```java:ViewModelProvider.NewInstanceFactory
public static class NewInstanceFactory implements Factory {
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        //noinspection TryWithIdenticalCatches
        try {
            return modelClass.newInstance();
        } catch (InstantiationException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException("Cannot create an instance of " + modelClass, e);
        }
    }
}
```

それぞれの実装において注目したいのは、`DefaultFactory`の`return modelClass.getConstructor(Application.class).newInstance(mApplication);`の部分と、`ViewModelProvider.NewInstanceFactory`の`return modelClass.newInstance();`の部分です。
その実装に注目すると、`sDefaultFactory`を使った場合、

- `AndroidViewModel`を継承した`ViewModel`の場合、コンストラクタに`Application`クラスが引数として渡され、インスタンスが生成される
- 上記ではない`ViewModel`の場合、引数なしのコンストラクタが呼ばれ、インスタンスが生成される

という挙動になります。

したがって、次の`ViewModel`クラスのように、`Application`クラス以外をコンストラクタの引数としたい場合は`DefaultFactory`ではない、独自の`ViewModelProvider.Factory`が必要になります。

```kotlin:MainViewModel.kt
class MainViewModel constructor(private val repository: GitHubRepository) : ViewModel() {
```

上記の`MainViewModel`クラスのインスタンスを生成できるように、独自の`ViewModelProvider.Factory`を作ると以下のようになります。

```java:ViewModelFactory.java
public class ViewModelFactory extends ViewModelProvider.NewInstanceFactory {

    @SuppressLint("StaticFieldLeak")
    private static volatile ViewModelFactory INSTANCE;

    private final Application mApplication;

    private final TasksRepository mTasksRepository;

    public static ViewModelFactory getInstance(Application application) {

        if (INSTANCE == null) {
            synchronized (ViewModelFactory.class) {
                if (INSTANCE == null) {
                    INSTANCE = new ViewModelFactory(application,
                            Injection.provideTasksRepository(application.getApplicationContext()));
                }
            }
        }
        return INSTANCE;
    }

    @VisibleForTesting
    public static void destroyInstance() {
        INSTANCE = null;
    }

    private ViewModelFactory(Application application, TasksRepository repository) {
        mApplication = application;
        mTasksRepository = repository;
    }

    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        if (modelClass.isAssignableFrom(StatisticsViewModel.class)) {
            //noinspection unchecked
            return (T) new StatisticsViewModel(mApplication, mTasksRepository);
        } else if (modelClass.isAssignableFrom(TaskDetailViewModel.class)) {
            //noinspection unchecked
            return (T) new TaskDetailViewModel(mApplication, mTasksRepository);
        } else if (modelClass.isAssignableFrom(AddEditTaskViewModel.class)) {
            //noinspection unchecked
            return (T) new AddEditTaskViewModel(mApplication, mTasksRepository);
        } else if (modelClass.isAssignableFrom(TasksViewModel.class)) {
            //noinspection unchecked
            return (T) new TasksViewModel(mApplication, mTasksRepository);
        }
        throw new IllegalArgumentException("Unknown ViewModel class: " + modelClass.getName());
    }
}
```
引用元 : https://github.com/googlesamples/android-architecture/blob/todo-mvvm-live/todoapp/app/src/main/java/com/example/android/architecture/blueprints/todoapp/ViewModelFactory.java

メソッド`public <T extends ViewModel> T create(Class<T> modelClass)`内の実装に注目してください。
このメソッド内で、if文による場合分けが必要になります。
また、メソッド`getInstance`で行っているように、`ViewModelFactory`自身をシングルトンにする工夫なども必要になります。

`Application`クラス以外をコンストラクタの引数としたい場合、このような手間を省くためにDagger2を使うことができます。

## Dagger2のMultibinding機能を使ってViewModelのインスタンスを生成する

Dagger2を利用して、独自の`ViewModelProvider.Factory`を使う場合はMultibinding機能を使います。

https://google.github.io/dagger/multibindings.html

```kotlin:ViewModelKey.kt
@MustBeDocumented
@Target(AnnotationTarget.FUNCTION)
@Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)
```
上記のようにキーを指定するためのアノテーションを定義して、Module内には以下のように記述します。

```kotlin:MainModule.kt
@Module
internal abstract class MainModule {
  @Binds
  @IntoMap
  @ViewModelKey(MainViewModel::class) //Key名
  abstract fun bindMainViewModel(viewModel: MainViewModel): ViewModel
}
```
上記のように記述することで、`ViewModel`クラスをinjectしたい場合、`MainViewModel::class`をキー名とすれば、`MainViewModel`のインスタンスが生成されinjectされることになります。

このとき、独自の`ViewModelProvider.Factory`は以下のように定義します。

```kotlin:ViewModelFactory.kt
class ViewModelFactory @Inject constructor(
  private val creators: Map<Class<out ViewModel>,
  @JvmSuppressWildcards Provider<ViewModel>>
) : ViewModelProvider.Factory {

  @Suppress("UNCHECKED_CAST")
  override fun <T : ViewModel> create(modelClass: Class<T>): T {
    var creator: Provider<ViewModel>? = creators[modelClass]
    if (creator == null) {
      for ((key, value) in creators) {
        if (modelClass.isAssignableFrom(key)) {
          creator = value
          break
        }
      }
    }
    if (creator == null) throw IllegalArgumentException("unknown model class " + modelClass)
    try {
      return creator.get() as T
    } catch (e: Exception) {
      throw RuntimeException(e)
    }
  }
}
```

コンストラクタの引数にある`Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>`型の`creators`に、`MainModule`クラスの記述に応じたマップがinejectされます。

>`ViewModel`クラスをinjectしたい場合、`MainViewModel::class`をキー名とすれば、`MainViewModel`のインスタンスが生成されinjectされることになります。

と先程書きましたが、それはすなわち、`var creator: Provider<ViewModel>? = creators[modelClass]`の箇所で、`modelClass``MainViewModel::class`が指定されれば、`creator`は`MainViewModel`型を返す`Provider`ということになります。実際に、`return creator.get() as T`として、`creator`から`MainViewModel`型のインスタンスを取得し、キャストした上で返しています。

ここでの`Provider`はDagger2内のインタフェースで、Provider injectionの機能を利用するためのものです。

```java:Provider.java
public interface Provider<T> {

    /**
     * Provides a fully-constructed and injected instance of {@code T}.
     *
     * @throws RuntimeException if the injector encounters an error while
     *  providing an instance. For example, if an injectable member on
     *  {@code T} throws an exception, the injector may wrap the exception
     *  and throw it to the caller of {@code get()}. Callers should not try
     *  to handle such exceptions as the behavior may vary across injector
     *  implementations and even different configurations of the same injector.
     */
    T get();
}
```

コメントにあるように、`Provider`は型パラメータに指定した型のインスタンスを、依存性を解決した上で返すためのクラスです。Provider Injectionについては以下の記事が参考になるかと思います。

- [Dagger2の公式ドキュメントを読んで基礎を理解してみる](https://qiita.com/takahirom/items/aa9087b075cc9b7249b6#provider-injections)

このとき、Dagger2によって生成されるコードは以下のようになっていて、

```java:DaggerAppComponent.java
//いろいろ省略

private MainViewModel_Factory mainViewModelProvider;

private Map<Class<? extends ViewModel>, Provider<ViewModel>>
    getMapOfClassOfAndProviderOfViewModel() {
  return Collections.<Class<? extends ViewModel>, Provider<ViewModel>>singletonMap(
      MainViewModel.class, (Provider) mainViewModelProvider);
}
private ViewModelFactory getViewModelFactory() {
  return new ViewModelFactory(getMapOfClassOfAndProviderOfViewModel());
}
```

```java:MainViewModel_Factory.java
public final class MainViewModel_Factory implements Factory<MainViewModel> {
  private final Provider<GitHubRepository> repositoryProvider;

  public MainViewModel_Factory(Provider<GitHubRepository> repositoryProvider) {
    this.repositoryProvider = repositoryProvider;
  }

  @Override
  public MainViewModel get() {
    return new MainViewModel(repositoryProvider.get());
  }

  public static MainViewModel_Factory create(Provider<GitHubRepository> repositoryProvider) {
    return new MainViewModel_Factory(repositoryProvider);
  }
}
```

`Collections.<Class<? extends ViewModel>, Provider<ViewModel>>singletonMap(MainViewModel.class, (Provider) mainViewModelProvider);`が`ViewModelFactory`のコンストラクタ引数に渡される実態となるインスタンスで、`MainViewModel.class`がキー、`MainViewModel`を生成する`mainViewModelProvider`(＝`MainViewModel_Factory`型のメンバ変数`mainViewModelProvider`)がその値となっていることがわかります。

### Dagger2を使ったViewModelProvider.Factoryの注意点

先程の`ViewModelFactory`のコンストラクタの引数に`@JvmSuppressWildcards`がついています。
これがないとビルドエラーとなります。
Dagger2によって生成されたJavaコードを見ればわかりますが、`ViewModelFactory`のコンストラクタに代入される`creator`は`Map<Class<? extends ViewModel>, Provider<ViewModel>>`型(Javaでの表記)です。

```kotlin
creators : Map<Class<out ViewModel>, Provider<ViewModel>>
```
一方で、`@JvmSuppressWildcards`の無い、上記のコードをコンパイルすると`Map<Class<? extends ViewModel>,? extends Provider<ViewModel>>`型(Javaでの表記)となります。

これに関しては以下の記事が参考になると思います。

- [Kotlin - Javaとの相互運用](https://qiita.com/k5n/items/ceb1f921b27d62fc9fcb#%E3%82%B8%E3%82%A7%E3%83%8D%E3%83%AA%E3%82%AF%E3%82%B9%E3%81%AE%E5%A4%89%E6%80%A7)

さらに、関数`create`の中の実装についてですが、`var creator: Provider<ViewModel>? = creators[modelClass]`として、一度`creators`から`Provider<ViewModel>`型の`creator`を取得してから、`creator`が`null`なら再度マップ内を探索しています。
手元では`creator`が`null`とならなかったので、後続の処理が必要な理由がいまいち不明です。
参考となるリポジトリでも、[最初のcommit](https://github.com/googlesamples/android-architecture-components/commit/2e09898630783bf863ddd82f1c30817da9a2fe32#diff-438c9a51a8fe09c1381822c7d5318d74)からそのようになっていました。
こちらに関してもしご存知の方がいたら[Twitter](https://twitter.com/satorufujiwara)やコメントなどで教えてください。

# SubComponetを使うかどうか

[GitHubBrowserSample](https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample)の[GitHubViewModelFactory](https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/viewmodel/GithubViewModelFactory.java)には`@Singleton`というアノテーションがついていますが、[kotlin-architecture-components](https://github.com/satorufujiwara/kotlin-architecture-components)の[ViewModelFactory](https://github.com/satorufujiwara/kotlin-architecture-components/blob/master/app/src/main/java/jp/satorufujiwara/kotlin/di/ViewModelFactory.kt)にはついていません。
前者は文字通りアプリ内で唯一のインスタンスを持ちますが、後者はインスタンスが必要な時に都度生成をしています。
この違いはSubComponentを使うかどうかの違いによるものです。

## ViewModelProvider.Factoryをシングルトンにする場合

まずは`@Singleton`をつけた場合についてどうなるか考えます。この場合、そのコンストラクタにinejectされる`Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>>`型の引数`creators`もシングルトンになります。
したがってその元となるModuleの定義も以下のようにまとめて書く必要があります。

```java:ViewModelModule.java
@Module
abstract class ViewModelModule {
    @Binds
    @IntoMap
    @ViewModelKey(UserViewModel.class)
    abstract ViewModel bindUserViewModel(UserViewModel userViewModel);

    @Binds
    @IntoMap
    @ViewModelKey(SearchViewModel.class)
    abstract ViewModel bindSearchViewModel(SearchViewModel searchViewModel);

    @Binds
    @IntoMap
    @ViewModelKey(RepoViewModel.class)
    abstract ViewModel bindRepoViewModel(RepoViewModel repoViewModel);

    @Binds
    abstract ViewModelProvider.Factory bindViewModelFactory(GithubViewModelFactory factory);
}
```
引用元 : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/ViewModelModule.java

同様にFragmentの定義、Activityの定義を以下のように書きます。

```java:FragmentBuildersModule.java
@Module
public abstract class FragmentBuildersModule {
    @ContributesAndroidInjector
    abstract RepoFragment contributeRepoFragment();

    @ContributesAndroidInjector
    abstract UserFragment contributeUserFragment();

    @ContributesAndroidInjector
    abstract SearchFragment contributeSearchFragment();
}
```
引用元 : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/FragmentBuildersModule.java

```java:MainActivityModule.java
@Module
public abstract class MainActivityModule {
    @ContributesAndroidInjector(modules = FragmentBuildersModule.class)
    abstract MainActivity contributeMainActivity();
}
```
引用元 : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/MainActivityModule.java

`FragmentBuildersModule`にはアプリ内に存在するinjectが必要なすべてのFragmentについて記述することになります。
Activityに関してはActivityごとにModuleを分けて書いていますが、それらのModuleへの参照を`AppComponent`に書くことになります。

```java:AppComponents.java
@Singleton
@Component(modules = {
        AndroidInjectionModule.class,
        AppModule.class,
        MainActivityModule.class
})
public interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance Builder application(Application application);
        AppComponent build();
    }
    void inject(GithubApp githubApp);
}
```
引用元 : https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/di/AppComponent.java

全く問題のない方法ですが、Activityを追加する際には以下の3箇所に分けて記述を追加する必要があります。

- Activityの定義は各ActivityごとのModuleと`AppComponent`に
- Fragmentの定義は`FragmentBuildersModule`に
- ViewModelの定義は`ViewModelModule`に

このように記述を追加しなければいけない箇所が分かれているのは、場合によってはつらいかもしれません。
また、3つともがアプリ全体の構造を知っているクラスということになります。

## ViewModelProvider.FactoryをSubComponentごとに生成する場合

SubComponentを使うことで、上記のうち、FragmentとViewModelの定義を1箇所にまとめることができます。
ActivityごとにModuleを作るのは同様ですが、その配下にFragmentやViewModelに関しての定義も入れる、という実装です。

ただ、そのModuleで定義されたSubComponentごとに`ViewModelProvider.Factory`が生成されることになるので、Factoryのインスタンスをシングルトンにすることはできません。
SubComponetを使う場合は以下のように`@ContributesAndroidInjector`アノテーションの引数にサブコンポーネント用のModuleを指定します。

```kotlin:UiModule.kt
@Module
internal abstract class UiModule {

  @Binds
  abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

  @ContributesAndroidInjector(modules = arrayOf(MainModule::class))
  internal abstract fun contributeMainActivity(): MainActivity

}
```

`MainModule`にはこの`MainActivity`に所属するFragmentやViewModelの定義を書きます。

```kotlin:MainModule.kt
@Module
internal abstract class MainModule {

  @Binds
  @IntoMap
  @ViewModelKey(MainViewModel::class)
  abstract fun bindMainViewModel(viewModel: MainViewModel): ViewModel

  @ContributesAndroidInjector
  abstract fun contributeMainFragment(): MainFragment

}
```

このようにすることで、Dagger2によって生成されるコードは以下のようになり、SubComponentが使われていることがわかると思います。

```java:DaggerAppComponent.java

private final class MainActivitySubcomponentImpl
      implements UiModule_ContributeMainActivity$app_debug.MainActivitySubcomponent {
    private GitHubRepository_Factory gitHubRepositoryProvider;
    private MainViewModel_Factory mainViewModelProvider;

    private Provider<MainModule_ContributeMainFragment.MainFragmentSubcomponent.Builder>
        mainFragmentSubcomponentBuilderProvider;

    private MainActivitySubcomponentImpl(MainActivitySubcomponentBuilder builder) {
      initialize(builder);
    }

    private Map<Class<? extends ViewModel>, Provider<ViewModel>>
        getMapOfClassOfAndProviderOfViewModel() {
      return Collections.<Class<? extends ViewModel>, Provider<ViewModel>>singletonMap(
          MainViewModel.class, (Provider) mainViewModelProvider);
    }

    private ViewModelFactory getViewModelFactory() {
      return new ViewModelFactory(getMapOfClassOfAndProviderOfViewModel());
    }
    
    //省略
}

```

このコードの`getViewModelFactory()`というメソッド内を見ればわかるように、このSubComponent内では`ViewModelFactory`のインスタンスが都度生成されています。
そして、ActivityやFragment内で`MainViewModel`のインスタンスを取得する処理は以下のようになります。

```kotlin:MainActivity.kt
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory

viewModel = ViewModelProviders.of(this, viewModelFactory).get(MainViewModel::class.java)
```
```MainFragment.kt
@Inject lateinit var viewModelFactory: ViewModelProvider.Factory

viewModel = ViewModelProviders.of(activity!!, viewModelFactory).get(MainViewModel::class.java)
```
この時、Dagger2によってinjectされる`viewModelFactory`のインスタンスは`MainActivity`内と、`MainFragment`内とで、別々のインスタンスとなります。
しかし、`MainFragment`内でも`ViewModelProviders::of`の引数にActivityを指定しているので、`MainViewModel`のインスタンスは`MainActivity`内でも`MainFragment`内でも同一のインスタンスが取得されることになります。
これはすでに説明したように、取得できる`FragmentManager`が同一であり、先に呼ばれた`ViewModelProviders:of`の内部で`MainViewModel`のインスタンスが生成され、次回以降もそのインスタンスが利用されるためです。
したがって、引数として与えた`ViewModelProvider.Factory`型のクラスが実際に使われるのは先に呼ばれた1回のみなので、Activity内とFragment内のそれぞれでのインスタンスが異なっていても`MainViewModel`クラスのインスタンスは同一、ということになります。

Dagger2においてはSubComponentを利用する際に、独自の`Scope`を指定することで、そのインスタンスを同一に保つことができますが、`ViewModel`に関してはその`Scope`も不要ということになります。
[Fluxアーキテクチャを利用した例](https://github.com/satorufujiwara/android-flux-architecture/tree/master/flux-arch)においては、`MainDispatcher`クラスのインスタンスをSubComponent内で同一にするために、以下のように`PerActivityScope`という`Scope`を用いています。

```kotlin:MainModule.kt
@Module
internal abstract class MainModule {

  @Binds
  @IntoMap
  @ViewModelKey(MainStore::class)
  abstract fun bindMainStore(viewModel: MainStore): ViewModel

  @ContributesAndroidInjector
  abstract fun contributeRepoDetailDialogFragment(): RepoDetailDialogFragment
}

@Module
internal class MainDispatcherModule {

  @PerActivityScope
  @Provides
  fun provideMainDispatcher() = MainDispatcher()

}
```
引用元 : https://github.com/satorufujiwara/android-flux-architecture/blob/master/flux-arch/app/src/main/java/jp/satorufujiwara/flux/di/modules/MainModule.kt

このサンプルの詳細については以下の記事に詳しく書いています。

- [Architecture Components + Flux (+ Kotlin)によるAndroidアプリ設計](https://qiita.com/satorufujiwara/items/dfc55fc2e0316ae5d8fe)

まとめると、SubComponentを利用した場合は、

- ActivityごとにSubComponentを作り、`MainModule`のようにその画面に属する依存性のための処理をまとめることができる
- すべてのActivityの種類を知っているのは、`UiModule`のような1つのクラスだけになる
- ただし、都度`ViewModelProvider.Factory`型のインスタンスが生成されることになる

となり、好みの問題かもしれませんが「アプリ全体の構造を知っているクラス」を1つに絞ることができます。

# Dagger2によってViewModelをInjectする

すでに説明したように`ViewModel`クラスは`ViewModelProviders:of`経由で取得する必要があります。
Dagger2と併用した場合に、この`ViewModel`クラスだけ`@Inject`アノテーションがついてないことで、間違いが起きる可能性があります。
`ViewModel`型のクラスについてもDagger2を用いてinjectする方法を同僚の[stsn](https://qiita.com/stsn)さんに教えていただきました。

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">AACのViewModel使うとDaggerのフローから外れるの微妙。Factory配るパターンがメジャーなようにみえるけど、それだとViewModelを直接 [at]Injectしたときにおかしくなるから、間違った使いかたが出来るので良くない</p>&mdash; Sato Shun△ (@stsn_jp) <a href="https://twitter.com/stsn_jp/status/952749552154456064?ref_src=twsrc%5Etfw">2018年1月15日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

```kotlin:MainModule.kt
@Module
abstract class ActivityProviderModule<in T : FragmentActivity, VM : ViewModel>(
    private val kclass: Class<VM>
) {
  @Provides
  fun providedActivity(activity: T): FragmentActivity = activity

  @Provides
  fun provideClass(): Class<VM> = kclass

  @Provides
  fun provideViewModel(
      activity: FragmentActivity,
      kclass: Class<VM>,
      factory: ViewModelInjectorFactory<VM>
  ): VM {
    return ViewModelProviders.of(activity, factory).get(kclass)
  }
}
```
引用元 : https://github.com/satorufujiwara/android-flux-architecture/blob/master/flux-arch/app/src/main/java/jp/satorufujiwara/flux/di/modules/MainModule.kt

上記のように、`ViewModelsProviders::of`や`ViewModelProvider::get`に必要な引数である`FragmentActivity`、`Class<ViewModel>`についてもDagger2を用いてinjectすることによって`ViewModel`も`@Inject`というアノテーションをつけて、Dagger2によるinjectが可能になります。

# まとめ

- Architecture Components を Dagger2 と併用する際はMultibinding機能を用いた独自の`ViewModelProvider.Factory`を使う
- SubComponetを用いてみたり、`ViewModel`もDagger2を用いてinjectするなど、まだまだ改善の余地がありそう