TL; DR
ModuleでActivityから必要な値を取り出せます。
@Module
class YourModule {
@Provides
SomeArgument provideSomeArgument(YourActivity activity) {
return activity.someArgumentYouWant();
}
}
AndroidInjectionとは
(※ Dagger 2.11時点の情報です。)
Dagger 2.10から、AndroidInjectionModule(もしくはAndroidSupportInjectionModule)を使用することでより単純に依存性注入ができるようになりました。
これ↓が、
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
}
}
こう↓なります。
public class YourActivity extends Activity {
public void onCreate(Bundle savedInstanceState) {
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
}
}
ActivityからComponentやModuleに引数を渡す
AndroidInjectionを使用する前
何らかの事情でActivityからオブジェクトグラフに値を追加する必要があった場合、Component.BuilderやModuleのコンストラクタを経由していたと思います。
Component.Builderを経由する方法
Component作成時に必要な値をオブジェクトグラフに追加します。
@Module
class SubActivityModule {
@Provides
@PerActivity
SubActivityViewModel provideSubActivityViewModel(@UserName String userName) { // <-- ここでActivityに渡された引数を使いたい
return new SubActivityViewModel(userName);
}
}
@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);
}
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のインスタンス化時に必要な値を渡します。
@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);
}
}
@PerActivity
@Subcomponent(modules = SubActivityModule.class)
public interface SubActivityComponent {
@Subcomponent.Builder
interface Builder {
Builder subActivityModule(SubActivityModule module); // <-- 明示的にModuleを受け取る
SubActivityComponent build();
}
void inject(SubActivity activity);
}
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から必要な値を取り出します。
@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);
}
}
@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();
}
}
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フィールドを経由しても可能です。
public String userName;
@Override
protected void onCreate(Bundle savedInstanceState) {
userName = getIntent().getStringExtra(SubActivity.EXTRA_NAME_USER_NAME);
AndroidInjection.inject(this);
super.onCreate(savedInstanceState);
// (後略)
@Provides @PerActivity @UserName
String provideUserName(SubActivity activity) {
return activity.userName;
}
サンプルプロジェクト
参考にさせていただいたサイト
Dagger & Android --- Dagger ‡ A fast dependency injector for Android and Java.
Android and Dagger 2.10 AndroidInjector – AndroidPub
Yukiの枝折: DaggerのAndroid拡張を導入する(v2.11-rc1)