Dagger2のAndroidサポートが何をしているのか理解する


# 概要

Dagger2では2.10からdagger.androidが入り、2.11でそれがさらに使いやすくなりました。
ここでは生成されたコードを見て、何をしているのかの説明を書いておきます。
ついでにKotlinでのandroidサポートを使った導入の仕方も記述しておきます。

# 導入

## Gradle

```build.gradle
buildscript {
    ext.dagger_version = "2.12"
	・・・
```

```app/build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'

・・・
dependencies {
・・・
    kapt "com.google.dagger:dagger-compiler:$dagger_version"
    kapt "com.google.dagger:dagger-android-processor:$dagger_version"
    implementation "com.google.dagger:dagger:$dagger_version"
    implementation "com.google.dagger:dagger-android:$dagger_version"
・・・
```

## Module

以下が、Android Supportで追加されたModuleの書き方になります。

```AndroidModule.kt
@Module
abstract class AndroidModule {

    @ContributesAndroidInjector
    abstract fun contributeMainActivity(): MainActivity
}
```

```@ContributesAndroidInjector``` が2.11からできたAPIです。
これにより、2.10で自分で記述していたコードを生成してくれます。
自動生成されたソースは後ほど説明します。

## Component

```AppComponent.kt
@Singleton
@Component(modules = arrayOf(AndroidInjectionModule::class, AndroidModule::class))
interface AppComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: App): Builder
        fun build(): AppComponent
    }
    fun inject(app: App)
}
```

```AndroidInjectionModule::class``` がミソです。2.10から追加されました。
```@BindsInstance```は、2.9から追加されました。自分でコンポーネントを構築するときに、これを指定したメソッドを呼び出すことで、引数をコンポーネントにInjectできるようになります。


どういうことかというと、```@BindsInstance fun application(application: App): Builder```を書かないと例えば、以下のようにContextをInjectしようとしてもコンパイルエラーになります。

```
@Module
class AppModule {
    @Provides
    fun provideContext(application: App) = application.applicationContext
}

class MainDao @Inject constructor() {
    @Inject
    lateinit var context: Context
```

```@BindsInstance fun application(application: App): Builder```を記述し、Applicationクラスで設定することで、ModuleでDIされた状態で利用できるようになるということです。

## Application

AppComponentから自動生成されたクラス```DaggerAppComponent```を使ってコンポーネント構築します。

```App.kt
class App : Application(), HasActivityInjector {

    @Inject lateinit var dispatchingAndroidInjector: DispatchingAndroidInjector<Activity>

    override fun activityInjector() = dispatchingAndroidInjector

    override fun onCreate() {
        super.onCreate()

        val objectGraph = DaggerAppComponent
                .builder()
                .application(this)
                .build()
        objectGraph.inject(this)
    }
}
```

AppComponentで指定した```@BindsInstance```のメソッドを使って、AppクラスをModuleで利用できるようにしています。(```application(this)```の部分です。)
また、```dagger.android.HasActivityInjector```インターフェイスが重要です。これは次のActivityのソースとともに説明します。

## Activity

Androidサポートのおかげで```dagger.android.AndroidInjection.inject(this)```だけを書けば、DIされるようになりました。

```MainActivity.kt
lass MainActivity : AppCompatActivity() {
    @Inject
    lateinit var viewModel: MainViewModel
    
    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
    ・・・      
```

ついでにその他のクラスも載せておきます。

```MainViewModel.kt
class MainViewModel @Inject constructor() {
    @Inject
    lateinit var domain: MainDomain 
    ・・・ 
```

```dagger.android.AndroidInjection.inject(this)``` が具体的に何をしているかというと、Applicationクラス(ここの場合はApp.ktクラス)で```dagger.android.HasActivityInjector```が実装されていれば、```dagger.android.DispatchingAndroidInjector```を使って引数のActivity(ここではMainActivity)をComponet(これは依存を解決するためのクラス。別名ObjectGraph。)に入れています。（```@ContributesAndroidInjector```を書いていないとここでassertエラーになります。）
そして、Activityで```@Inject```しているフィールドにInjectしてくれます。

もう少し具体的にいうと```dagger.android.DispatchingAndroidInjector ```が、MainActivityをキーにModuleで定義した```@ContributesAndroidInjector```によって自動生成されたコード```MainActivitySubcomponentBuilder```、さらに、Builderがインスタンスする同じく自動生成されたクラス```MainActivitySubcomponentImpl```（```dagger.android.AndroidInjector```の実装クラス）を生成し、このクラスがそれぞれのクラスをInjectをします。

説明した対応のコードの一部が以下です。
ActivityのAndroidInjection.inject(this)が呼ばれた先に以下のmaybeInjectメソッドがあります。

```dagger.android.DispatchingAndroidInjector.java
 public boolean maybeInject(T instance) { // ① instance=MainActivity
    Provider<AndroidInjector.Factory<? extends T>> factoryProvider =
        injectorFactories.get(instance.getClass()); 
    if (factoryProvider == null) {
      return false;
    }

    @SuppressWarnings("unchecked")
    AndroidInjector.Factory<T> factory = (AndroidInjector.Factory<T>) factoryProvider.get(); // ② factory=MainActivitySubcomponentBuilder
    
    try {
      AndroidInjector<T> injector =
          checkNotNull(
              factory.create(instance), // ③ new MainActivitySubcomponentImpl()             
              "%s.create(I) should not return null.",
              factory.getClass().getCanonicalName());

      injector.inject(instance); // ④
```

①の行の引数の```T instance```は、MainActivityです。
②の行の```AndroidInjector.Factory<T> factory```には、MainActivitySubcomponentBuilderが入ります。
③の行の```factory.create(instance)```でMainActivitySubcomponentImplがインスタンスされます。
④の行の```injector.inject(instance);```では、自動生成された```DaggerAppComponent```が保持する```MembersInjector<MainActivity>```(これも自動生成された```MainActivity_MembersInjector```が実装クラス)を使って、MainActivityにDIすべきクラスを設定しています。


# 自動生成されるコード

```@ContributesAndroidInjector``` によって生成されたコードは以下です。
バージョン2.10では、これを自分で記述する必要がありました。


```AndroidModule_ContributeMainActivity.java
@Module(subcomponents = AndroidModule_ContributeMainActivity.MainActivitySubcomponent.class)
public abstract class AndroidModule_ContributeMainActivity {
  private AndroidModule_ContributeMainActivity() {}

  @Binds
  @IntoMap
  @ActivityKey(MainActivity.class)
  abstract AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(
      MainActivitySubcomponent.Builder builder);

  @Subcomponent
  public interface MainActivitySubcomponent extends AndroidInjector<MainActivity> {
    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<MainActivity> {} // implemenets AndroidInjector.Factory
  }
}
```

```@Binds``` は、超簡単に説明すると以下の定型コードを書かないで済むようにするアノテーションです。

```java
@Provides
AndroidInjector.Factory<? extends Activity> bindAndroidInjectorFactory(){
    return new MainActivitySubcomponent.Builder()
}
```

実際は、```MainActivitySubcomponent.Builder``` もabstractなので必要なメソッドを実装しないといけませんが、そういうことです。


```@IntoMap``` と```@ActivityKey``` はセットで利用するものです。ここで指定したものが、```dagger.android.DispatchingAndroidInjector```で保持されるMapになります。(このMapが最終的に重要になります)

```@ActivityKey``` で指定した値（この場合は、MainActivity.class）がキーになります。値は、メソッドの戻り値（この場合は、MainActivitySubcomponent.Builderになります。ちなみにこのBuilderはAndroidInjector.Factoryの実装になります。


以下がAppComponentから自動生成された対象の部分です。

```DaggerAppComponent.java
 ・・・
 private Provider<AndroidInjector.Factory<? extends Activity>> bindAndroidInjectorFactoryProvider;
 ・・・
     @Override
    public AppComponent build() {
      if (application == null) {
        throw new IllegalStateException(App.class.getCanonicalName() + " must be set");
      }
      return new DaggerAppComponent(this);
    }
 ・・・ 
  private DaggerAppComponent(Builder builder) {
    assert builder != null;
    initialize(builder);
  }

  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {

    this.mainActivitySubcomponentBuilderProvider =
        new dagger.internal.Factory<
            AndroidModule_ContributeMainActivity.MainActivitySubcomponent.Builder>() {
          @Override
          public AndroidModule_ContributeMainActivity.MainActivitySubcomponent.Builder get() {
            return new MainActivitySubcomponentBuilder();
          }
        }; // 参

    this.bindAndroidInjectorFactoryProvider = (Provider) mainActivitySubcomponentBuilderProvider; // 弐

    this.mapOfClassOfAndProviderOfFactoryOfProvider =
        MapProviderFactory
            .<Class<? extends Activity>, AndroidInjector.Factory<? extends Activity>>builder(1)
            .put(MainActivity.class, bindAndroidInjectorFactoryProvider)
            .build(); // 壱 bindAndroidInjectorFactoryProvider=dagger.internal.Factory() implements Providerの匿名クラス。上記弐,参、参照

    this.dispatchingAndroidInjectorProvider =
        DispatchingAndroidInjector_Factory.create(mapOfClassOfAndProviderOfFactoryOfProvider);

    this.appMembersInjector = App_MembersInjector.create(dispatchingAndroidInjectorProvider);
  }
  ・・・
```

重要と説明した「MainActivity.classがキーで、値がMainActivitySubcomponent.Builderのmap」部分を具体的に見ていきます。
壱のmapの値に指定しているbindAndroidInjectorFactoryProviderは
弐を見るとmainActivitySubcomponentBuilderProviderになります。
さらにmainActivitySubcomponentBuilderProviderは、参で```dagger.internal.Factory```の匿名クラスになっています。
```dagger.internal.Factory```は```javax.inject.Provider```を継承していて、getで返すインスタンスは、```MainActivitySubcomponentBuilder```クラスです。
```MainActivitySubcomponentBuilder```の親クラスが```MainActivitySubcomponent.Builder```になります。

ちなみにDaggerでは、```javax.inject.Provider#get()```で取得できるクラスがInject可能であれば、ProviderをDI対象できます。
つまり、以下の定義は不要ということです。

```
   @Provides
   fun provideMainActivitySubcomponentBuilderProvider() = object: Provider<MainActivitySubcomponentBuilder> {
        override fun get(): MainActivitySubcomponentBuilder {
            return MainActivitySubcomponentBuilder()
        }
    }
```

なので、キーがMainActivityで、値が```Provider<AndroidInjector.Factory<? extends Activity>>```が成立するのです。

続きです。DaggerAppComponent.javaの続きです。

```DaggerAppComponent.java
  private final class MainActivitySubcomponentBuilder
      extends AndroidModule_ContributeMainActivity.MainActivitySubcomponent.Builder {
    private MainActivity seedInstance;

    @Override
    public AndroidModule_ContributeMainActivity.MainActivitySubcomponent build() {
      if (seedInstance == null) {
        throw new IllegalStateException(MainActivity.class.getCanonicalName() + " must be set");
      }
      return new MainActivitySubcomponentImpl(this); // 「ア」
    }

    @Override
    public void seedInstance(MainActivity arg0) {
      this.seedInstance = Preconditions.checkNotNull(arg0);
    }
  }

  private final class MainActivitySubcomponentImpl
      implements AndroidModule_ContributeMainActivity.MainActivitySubcomponent {
    private MembersInjector<MainViewModel> mainViewModelMembersInjector;

    private Provider<MainViewModel> mainViewModelProvider;

    private MembersInjector<MainActivity> mainActivityMembersInjector;

    private MainActivitySubcomponentImpl(MainActivitySubcomponentBuilder builder) {
      assert builder != null;
      initialize(builder);
    }

    @SuppressWarnings("unchecked")
    private void initialize(final MainActivitySubcomponentBuilder builder) { // 「イ」

      this.mainViewModelMembersInjector =
          MainViewModel_MembersInjector.create(MainDomain_Factory.create()); 

      this.mainViewModelProvider = MainViewModel_Factory.create(mainViewModelMembersInjector);

      this.mainActivityMembersInjector = MainActivity_MembersInjector.create(mainViewModelProvider);
    }

    @Override
    public void inject(MainActivity arg0) {
      mainActivityMembersInjector.injectMembers(arg0); // 「ウ」
    }
  }
```

MainActivitySubcomponent.Builderは「ア」でMainActivitySubcomponentImplをインスタンスしています。
これを実際にインスタンスしているのは、```dagger.android.DispatchingAndroidInjector.java``` で説明した③の部分```factory.create(instance)``` で、これは結局は、```Activity#onCreate()``` の最初で呼ぶ```AndroidInjection.inject(this)``` から呼ばれることになります。

で、```MainActivitySubcomponentImpl``` がインスタンスされると「イ」のメソッドで```@Inject``` でDIしたいクラスのProviderを保持している~Injectorクラスを自動生成されたFactoryクラスでインスタンスして「ウ」で、渡ってきたActivityの```@Inject``` を記述したフィールドに設定しています。


「ウ」で利用されているMainActivity_MembersInjectorは以下です。

```MainActivity_MembersInjector.java
public final class MainActivity_MembersInjector implements MembersInjector<MainActivity> {
  private final Provider<MainViewModel> viewModelProvider;

  public MainActivity_MembersInjector(Provider<MainViewModel> viewModelProvider) {
    assert viewModelProvider != null;
    this.viewModelProvider = viewModelProvider;
  }

  public static MembersInjector<MainActivity> create(Provider<MainViewModel> viewModelProvider) {
    return new MainActivity_MembersInjector(viewModelProvider);
  }

  @Override
  public void injectMembers(MainActivity instance) {
    if (instance == null) {
      throw new NullPointerException("Cannot inject members into a null reference");
    }
    instance.viewModel = viewModelProvider.get();
  }
}
```

上記、viewModelProviderのインスタンスは以下です。

```MainViewModel_Factory.java
public final class MainViewModel_Factory implements Factory<MainViewModel> {
  private final MembersInjector<MainViewModel> mainViewModelMembersInjector;

  public MainViewModel_Factory(MembersInjector<MainViewModel> mainViewModelMembersInjector) {
    assert mainViewModelMembersInjector != null;
    this.mainViewModelMembersInjector = mainViewModelMembersInjector;
  }

  @Override
  public MainViewModel get() {
    return MembersInjectors.injectMembers(mainViewModelMembersInjector, new MainViewModel());
  }

  public static Factory<MainViewModel> create(
      MembersInjector<MainViewModel> mainViewModelMembersInjector) {
    return new MainViewModel_Factory(mainViewModelMembersInjector);
  }
}
```


# @Singleton


次のようにすると```@Singleton```になります。

```
@Module
class AppModule {
    @Singleton
    @Provides
    fun provideMainDomain() = MainDomain()
}
```

```
@Singleton
class MainDomain @Inject constructor()
```

```
@Singleton
@Component(modules = arrayOf(AndroidInjectionModule::class, AndroidModule::class, AppModule::class))
interface AppComponent 
・・・
```

使う側のコードはいつも通りです。

```
class MainViewModel @Inject constructor() {

    @Inject
    lateinit var domain: MainDomain
    ・・・
```

こうするとどうなるかを見てみましょう

まずは、付けなかった場合です。


```DaggerAppComponent.java
・・・
  private final class MainActivitySubcomponentImpl
      implements AndroidModule_ContributeMainActivity.MainActivitySubcomponent {
・・・      
    private void initialize(final MainActivitySubcomponentBuilder builder) { 

      this.mainViewModelMembersInjector =
          MainViewModel_MembersInjector.create(MainDomain_Factory.create());  // ここが違う
・・・          
```

MainDomainのProviderクラスが以下です。このクラスは```@Singleton```を付けた場合も存在します。

```MainDomain_Factory.java
public final class MainDomain_Factory implements Factory<MainDomain> {
  private static final MainDomain_Factory INSTANCE = new MainDomain_Factory();

  @Override
  public MainDomain get() {
    return new MainDomain();
  }

  public static Factory<MainDomain> create() {
    return INSTANCE;
  }
}
```

```MainViewModel_MembersInjector#create``` に渡す引数が、MainDomain_Factoryで、それはget()メソッドでMainDomainのインスタンス化して返します。Factory=Providerで、getが呼ばれるたびにインスタンスされます。

次は、```@Singleton``` を付けた場合です。
```MainViewModel_MembersInjector#create``` に渡すProviderが違います。


```DaggerAppComponent.java
      this.mainViewModelMembersInjector =
          MainViewModel_MembersInjector.create(DaggerAppComponent.this.provideMainDomainProvider); // ここが違う
```

```
  public static AppComponent.Builder builder() {
    return new Builder();
  }
  
  @SuppressWarnings("unchecked")
  private void initialize(final Builder builder) {
    ・・・
    this.provideMainDomainProvider =
     DoubleCheck.provider(AppModule_ProvideMainDomainFactory.create(builder.appModule));
```

この```DoubleCheck.provider()``` メソッドでSingleton対象のMainDomainを```instance``` フィールドで保持しておき、MainDomainProviderが呼ばれた時にそれを返すという仕組みです。

```DoubleCheck.java
public final class DoubleCheck<T> implements Provider<T>, Lazy<T> {
  private static final Object UNINITIALIZED = new Object();

  private volatile Provider<T> provider;
  private volatile Object instance = UNINITIALIZED;

  private DoubleCheck(Provider<T> provider) {
    assert provider != null;
    this.provider = provider;
  }

  @Override
  public T get() {
    Object result = instance;
    if (result == UNINITIALIZED) {
      synchronized (this) {
        result = instance;
        if (result == UNINITIALIZED) {
          result = provider.get(); // provider=AppModule_ProvideMainDomainFactory。ここでMainDomainがインスタンスされる
          Object currentInstance = instance;
          if (currentInstance != UNINITIALIZED && currentInstance != result) {
            throw new IllegalStateException("Scoped provider was invoked recursively returning "
                + "different results: " + currentInstance + " & " + result + ". This is likely "
                + "due to a circular dependency.");
          }
          instance = result; // ここでMainDomainがキャッシャされるので呼ばれるたびに同じインスタンスが返る
          provider = null;
        }
      }
    }
    return (T) result;
  }

  public static <T> Provider<T> provider(Provider<T> delegate) {
    checkNotNull(delegate);
    if (delegate instanceof DoubleCheck) {
      return delegate;
    }
    return new DoubleCheck<T>(delegate); // App.ktから呼ばれる
  }
```

ちなみにキャッシュしているDoubleCheckをインスタンスするのはApp.ktから呼ばれます。
activityなどは、```AndroidInjection.inject(this)``` の内部でprovideMainDomainProviderを使ってキャッシュからインスタンスを取得することになります。