21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-06-10

TL; DR

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

YourModule.java
@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);
  }
}

Dagger 2ドキュメントサイトより)

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

AndroidInjectionを使用する前

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

Component.Builderを経由する方法

Component作成時に必要な値をオブジェクトグラフに追加します。

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);
}
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のインスタンス化時に必要な値を渡します。

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);
    }
}
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);
}
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から必要な値を取り出します。

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);
    }
}
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();
    }
}
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フィールドを経由しても可能です。

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);
// (後略)
SubActivityModule.java
    @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)

21
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?