Dagger 2.10以降のAndroidInjectionでActivityからComponentやModuleに引数を渡す方法

# TL; DR
ModuleでActivityから必要な値を取り出せます。

```java:YourModule.java
@Module
class YourModule {
    @Provides
    SomeArgument provideSomeArgument(YourActivity activity) {
        return activity.someArgumentYouWant();
    }
}
```

# AndroidInjectionとは
（※ Dagger 2.11時点の情報です。）
Dagger 2.10から、AndroidInjectionModule（もしくはAndroidSupportInjectionModule）を使用することでより単純に依存性注入ができるようになりました。

これ↓が、

```java
public class FrombulationActivity extends Activity {
  @Inject Frombulator frombulator;

  @Override
  public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // DO THIS FIRST. Otherwise frombulator might be null!
    ((SomeApplicationBaseType) getContext().getApplicationContext())
        .getApplicationComponent()
        .newActivityComponentBuilder()
        .activity(this)
        .build()
        .inject(this);
    // ... now you can write the exciting code
  }
}
```

こう↓なります。

```java
public class YourActivity extends Activity {
  public void onCreate(Bundle savedInstanceState) {
    AndroidInjection.inject(this);
    super.onCreate(savedInstanceState);
  }
}
```

（[Dagger 2ドキュメントサイト](https://google.github.io/dagger//android.html#daggerandroid)より）


# ActivityからComponentやModuleに引数を渡す

## AndroidInjectionを使用する前
何らかの事情でActivityからオブジェクトグラフに値を追加する必要があった場合、Component.BuilderやModuleのコンストラクタを経由していたと思います。

### Component.Builderを経由する方法
Component作成時に必要な値をオブジェクトグラフに追加します。

```java:SubActivityModule.java
@Module
class SubActivityModule {
    @Provides
    @PerActivity
    SubActivityViewModel provideSubActivityViewModel(@UserName String userName) { // <-- ここでActivityに渡された引数を使いたい
        return new SubActivityViewModel(userName);
    }
}
```

```SubActivityComponent.java
@PerActivity
@Subcomponent(modules = SubActivityModule.class)
public interface SubActivityComponent {

    @Subcomponent.Builder
    interface Builder {
        @BindsInstance Builder userName(@UserName String userName); // <-- Activityから追加するオブジェクトを指定しておく
        SubActivityComponent build();
    }

    void inject(SubActivity activity);
}
```

```java:SubActivity.java
public class SubActivity extends AppCompatActivity {

    public static final String EXTRA_NAME_USER_NAME = "UserName";

    @Inject
    SubActivityViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        ActivitySubBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sub);

        String userName = getIntent().getStringExtra(EXTRA_NAME_USER_NAME); // <-- 値を取り出す

        ((App) getApplication()).getComponent()
                .subActivityComponentBuilder()
                .get()
                .userName(userName) // <-- オブジェクトグラフに追加
                .build()
                .inject(this);

        binding.setViewModel(viewModel);
    }
}
```

### Moduleのコンストラクタを経由する方法
Moduleのインスタンス化時に必要な値を渡します。

```java:SubActivityModule.java
@Module
public class SubActivityModule {
    private String mUserName;

    public SubActivityModule(String userName) { // <-- コンストラクタでActivityに渡された引数を受け取る
        mUserName = userName;
    }

    @Provides
    @PerActivity
    @UserName
    String provideUserName() { // <-- フィールドからオブジェクトグラフに追加する
        return mUserName;
    }

    @Provides
    @PerActivity
    SubActivityViewModel provideSubActivityViewModel(@UserName String userName) {
        return new SubActivityViewModel(userName);
    }
}
```

```java:SubActivityComponent.java
@PerActivity
@Subcomponent(modules = SubActivityModule.class)
public interface SubActivityComponent {
    @Subcomponent.Builder
    interface Builder {
        Builder subActivityModule(SubActivityModule module); // <-- 明示的にModuleを受け取る
        SubActivityComponent build();
    }
    void inject(SubActivity activity);
}
```

```java:SubActivity.java
public class SubActivity extends AppCompatActivity {
// （中略）
        ((App) getApplication()).getComponent()
                .subActivityComponentBuilder()
                .get()
                .subActivityModule(new SubActivityModule(userName)) // <-- Moduleのコンストラクタに値を渡す
                .build()
                .inject(this);
// （後略）
```

## AndroidInjectionを使用したとき
`AndroidInjection.inject(this)`を呼び出すだけなので、オブジェクトグラフに値を追加する隙間がありません。
AndroidInjectionによりActivityがオブジェクトグラフに追加されているので、Activityから必要な値を取り出します。

```java:SubActivityModule.java
@Module
class SubActivityModule {
    @Provides
    @PerActivity
    @UserName
    String provideUserName(SubActivity activity) { // <-- Activityを依存性解決に利用
        return activity.getIntent().getStringExtra(SubActivity.EXTRA_NAME_USER_NAME); // <-- 必要な値を取り出す
    }

    @Provides
    @PerActivity
    SubActivityViewModel provideSubActivityViewModel(@UserName String userName) {
        return new SubActivityViewModel(userName);
    }
}
```

```java:SubActivityComponent.java
@PerActivity
@Subcomponent(modules = SubActivityModule.class)
public interface SubActivityComponent extends AndroidInjector<SubActivity> {

    @Subcomponent.Builder
    abstract class Builder extends AndroidInjector.Builder<SubActivity> {

        @Override
        public abstract SubActivityComponent build();
    }
}
```

```java:SubActivity.java
public class SubActivity extends AppCompatActivity {

    public static final String EXTRA_NAME_USER_NAME = "UserName";

    @Inject
    SubActivityViewModel viewModel;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        AndroidInjection.inject(this); // <-- AndroidInjectionを使用
        super.onCreate(savedInstanceState);

        ActivitySubBinding binding = DataBindingUtil.setContentView(this, R.layout.activity_sub);
        binding.setViewModel(viewModel); // <-- 注入されてる
    }
}
```

publicフィールドを経由しても可能です。

```java:SubActivity.java
    public String userName;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        userName = getIntent().getStringExtra(SubActivity.EXTRA_NAME_USER_NAME);
        AndroidInjection.inject(this);
        super.onCreate(savedInstanceState);
// （後略）
```

```java:SubActivityModule.java
    @Provides @PerActivity @UserName
    String provideUserName(SubActivity activity) {
        return activity.userName;
    }
```

## サンプルプロジェクト
https://github.com/FlameArche/AndroidInjectionSample

# 参考にさせていただいたサイト
[Dagger & Android --- Dagger ‡ A fast dependency injector for Android and Java.](https://google.github.io/dagger//android.html)
[Android and Dagger 2.10 AndroidInjector – AndroidPub](https://android.jlelse.eu/android-and-dagger-2-10-androidinjector-5e9c523679a3#3e26)
[Yukiの枝折: DaggerのAndroid拡張を導入する(v2.11-rc1)](http://yuki312.blogspot.jp/2017/04/daggerandroidv211-rc1.html)