はじめに
dagger.androidを使用すると、
AndroidInjection.inject(this)
というようにActivity側は簡潔な記述になりますが、古いDaggerの実装で
(application as MyApplication).getAppComponent()
.mainActivityBuilder(MainActivityModule("hoge"))
.build()
.inject(this)
このようにActivityからModuleに何かしらの値を渡していると、dagger.androidに移行するときに同じような書き方ができなくて辛いです。
しかし、どうしてもActivityからModuleへ値を渡す必要がある、そんな状況に陥ってしまったので色々調べながら実装しました。
どうやるか
公式サイトのInjecting Activity objects
を参考にMainActivity用のSubcomponentを作成します。
1箇所だけ公式と違う実装があります。
@Subcomponent(modules = [MainActivityModule::class])
interface MainActivitySubcomponent: AndroidInjector<MainActivity> {
@Subcomponent.Builder
abstract class Builder : AndroidInjector.Builder<MainActivity>() {
abstract fun mainActivityModule(module: MainActivityModule): Builder
override fun seedInstance(instance: MainActivity?) {
mainActivityModule(MainActivityModule(instance!!.prefix))
}
}
}
作成したSubcomponentをActivityModuleに紐付けます。
@Module(subcomponents = [MainActivitySubcomponent::class])
interface ActivityModule {
@Binds
@IntoMap
@ClassKey(MainActivity::class)
fun bindMainActivity(builder: MainActivitySubcomponent.Builder): AndroidInjector.Factory<*>
}
AcitivityModuleはAppComponentのmodulesに定義します。
@Component(modules = [AndroidInjectionModule::class, AppModule::class, ActivityModule::class])
interface AppComponent {
fun inject(app: App)
}
特筆すべきはMainActivitySubcomponentのSubcomponent.Builder内にあるseedInstanceメソッドです。
seedInstanceメソッドはMainActivityを引数に持っているので、MainActivityのpublicなメンバ変数やメソッドを準備してあげれば参照できます。
MainActivity側は下記のようになっています。
class MainActivity : AppCompatActivity() {
@Inject
lateinit var injectionClassA: InjectionClassA
@Inject
lateinit var injectionClassB: InjectionClassB
public val prefix = "Android"
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val textView = findViewById<TextView>(R.id.text_view)
textView.setText("${injectionClassA.getHello()} ${injectionClassB.getDagger()} !")
}
}
今回は、prefixというメンバ変数を準備してseedInstanceメソッド内でModuleに渡しています。
注意点として、AndroidInjection.inject(this)
より前に渡す値を定義してあげないといけないです。
所感
MainActivityがModuleのことを知らなくてよくなったと思ったら、ModuleがMainActivityのメンバ変数を知ってる状態に変わっただけというオチですね。
一時回避策としてはありかもしれませんが、最終的にはModuleへ値を渡す必要がないようにModule内でnewするクラスのコンストラクタを見直したほうがよいかと思いました。
コードが一部だけだとわかりづらいのでGitHubにあげます。