個人的に、dagger.androidを使わないほうがシンプルなのでは?って気持ちが最近芽生え始めてます。
また最近は機能をモジュールに分割するのも流行ってるので、その際にDaggerをどう使うかを考える必要があります。
マルチモジュールの手法として、Dynamic Feature Module(DFM)とそうじゃない方法があって、モジュールの依存関係の方向が違うので、それによってDaggerの使い方が変わってきます。
(今回はDFMじゃないほうの話がメインです。)
Dynamic Feature Module
DFMを使うときはdagger.androidを使うことが不可能では無いですが、非常に厳しい感じです。
逆にdagger.androidを使わないと、すごくシンプルになります。
このあたりは、以下の記事を参考にしてください。
Library Module
DFMとは違う従来のやり方として、FeatureモジュールをLibrary Moduleとして分割する方法があります。
dagger.androidを使うときは各Featureモジュールのdaggerモジュールを作って、それをAppComponentですべて参照する方法が一番ラクかなと思います。
今回はdagger.android使わない方法です。
課題
Featureモジュールからappモジュールを参照できない状態になるので、Applicationクラスを取得してキャストするようなことができません。
そのため、AppComponent/CoreComponentのような共通のComponentを簡単には取得できません。
簡単な対応方法を説明します。ちょっと断片的なコードだと分かりにくいかもしれないので、最後にサンプルリポジトリのリンクを置いてるのでそっちも参照してください。
対応してみる
coreモジュール
どのモジュールからも使われるcoreモジュールを作成しておきます。これがあると色々と便利なので。
coreモジュール内で、以下のような感じで、ComponentとModuleを定義します。
次に各モジュールで使うScopeを定義しておきます。
appモジュール
ComponentとModuleの定義します。Moduleの定義は諸略して、Componentを見てきます。
dependencies
を使ってCoreComponentに依存するようにして、そこからも依存解決できるようにします。
次にApplicationクラスです。以下のような感じでCoreComponentを作成して参照できるようにします。
最後にActivityでinjectします。
appモジュールはこれで問題なく使えてます。
Featureモジュール
次にFeatureモジュールでもやっていきます。同じようにComponentを dependencies
を使って定義します。
これをActivityでInjectしようとしてみますが、Appクラスが参照できないのでビルドできません。
appモジュールでは良いのですが、FeatureモジュールではAppクラス経由でCoreComponentが取得することができません。
CoreComponentをFeatureモジュールからも取得できるようにする
これは至ってシンプルです。まずcoreモジュールの方で、以下のようなinterfaceを作ります。
次にAppクラスでこのinterfaceを実装して、CoreComponentを返すようにします。
あとはFeatureモジュールの方で、ApplicationクラスをこのinterfaceにキャストしてあげてCoreComponentを取得するだけです。
これで問題なくFeatureモジュールでもInjectできるようになります。