dagger-androidでDialogFragmentにInjectする

仕事で担当しているプロダクトではDI用のライブラリとしてDagger2のAndroid拡張(https://google.github.io/dagger/android)を使用しています。 先日DialogFragmentに対してDIを行う処理を書いたのですが、その際のやり方をまとめておきます。

Scopeの定義

このプロジェクトではDaggerのScopeとしてActivityScopeFragmentScopeのようなカスタムScopeを定義しています。

同じようにDialogFragment用のScopeとしてDialogFragmentScopeを定義します。

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface DialogFragmentScope {
} 

Component, Module定義

dagger-androidでは@ContributesAndroidInjectorアノテーションを用いてActivity, Fragmentなどのコンポーネント定義を行うことができます。 また、@ContributesAndroidInjectorアノテーションにmoduleパラメータを指定し、該当モジュール内で更に@ContributesAndroidInjectorの定義を行う事で、サブコンポーネントの定義を行うことができます。

これを利用して今回は以下のようなコンポーネント関係を構築します。

ActivityComponent → FragmentComponent → DialogFragmentComopnent

  • Application用のModule(Activity用のInjectorを定義)
@Module
@Suppress("unused")
interface ApplicationModule {
    @ActivityScope
    @ContributesAndroidInjector(modules = [MyActivityModule::class])
    fun contributeMyActivity(): MyActivity
}
  • Activity用のModule(Fragment用のInjectorを定義)
@Module
@Suppress("unused")
interface MyActivityModule {
    @FragmentScope
    @ContributesAndroidInjector(modules = [MyFragmentModule::class])
    fun contributeMyFragment(): MyFragment
}
  • Fragment用のModule(DialogFragment用のInjectorを定義)
@Module
@Suppress("unused")
interface MyFragmentModule {
    @DialogFragmentScope
    @ContributesAndroidInjector
    fun contributeMyDialogFragment(): MyDialogFragment
} 

Inject

DialogFragment側の実装ではDaggerAppCompatDialogFragmentもしくはDaggerDialogFragmentを利用します。 あとは普通に@Injectアノテーションを用いて使用したいクラスを注入すればOKです。

class MyDialogFragment : DaggerAppCompatDialogFragment() {
    @Inject
    lateinit var presenter: MyPresenter
}

ここでInjectされているMyPresenterがFragmentScopeやActivityScopeとなっている場合、上位のFragment/Activityとインスタンスが共有されますのでPresenter経由でFragmentを操作する事などが可能になります。