1
0

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.androidでActivityからModuleへ値を渡す

Posted at

はじめに

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箇所だけ公式と違う実装があります。

MainActivitySubcomponent.kt
@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に紐付けます。

ActivityModule.kt
@Module(subcomponents = [MainActivitySubcomponent::class])
interface ActivityModule {

    @Binds
    @IntoMap
    @ClassKey(MainActivity::class)
    fun bindMainActivity(builder: MainActivitySubcomponent.Builder): AndroidInjector.Factory<*>
}

AcitivityModuleはAppComponentのmodulesに定義します。

AppComponent.kt
@Component(modules = [AndroidInjectionModule::class, AppModule::class, ActivityModule::class])
interface AppComponent {

    fun inject(app: App)
}

特筆すべきはMainActivitySubcomponentのSubcomponent.Builder内にあるseedInstanceメソッドです。
seedInstanceメソッドはMainActivityを引数に持っているので、MainActivityのpublicなメンバ変数やメソッドを準備してあげれば参照できます。
MainActivity側は下記のようになっています。

MainActivity.kt
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にあげます。

1
0
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
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?