Dagger AndroidからHiltを段階的に移行する方法です。最初のいくつかの設定をすれば段階的に移行することができると思います。
サンプルプロジェクトを実際に段階的に移行したので、各ステップごとにその差分を見ながら確認してもらえると良いかなと思います。
サンプルプロジェクト
マルチモジュール構成のシンプルなサンプルになっています。
Componentの引数を不要にする
@Component.Factory
で、 @BindsInstance
で引数をもらってる場合は、この引数を使わないようにします。HiltではComponentが不要になるので、事前に対応しておきます。Context
についてはHiltでも扱えるので、これはそのままでも大丈夫です。
これに対応する方法としては、 DaggerのModuleからApplicationクラスにアクセスして、そこで生成したものを取得するようにする感じです。
こうすることでComponentの引数から削除することができます。
Hiltをbuild.gradleに追加
必要なHiltライブラリをbuild.gradleに追加します。これは特に説明は不要だと思います。各Gradleモジュールに対して追加します。
implementation 'com.google.dagger:hilt-android:2.30.1-alpha'
kapt 'com.google.dagger:hilt-android-compiler:2.30.1-alpha'
@InstallInを不要にする
Hiltをbuild.gradleに追加しただけだと、 @InstallIn
の設定がModuleにないためビルドが通りません。なので、このチェック一旦不要します。
各モジュールのbuild.gradleを以下のようにして無効にできます。
Hiltプラグインを追加
最後にappモジュールにプラグインを追加します。
ApplicationクラスのHilt移行
最初にApplicationクラスの移行からやっていきます。
Moduleを集約
@InstallIn
を不要にする設定しましたが、このままだとHiltが認識してくれないので、これを認識するように設定します。AppComponentに関連付けているすべてのModuleを集約したModuleを新しく作成します。
AppComponentを変更
AppComponentを修正して @EntryPoint
と @InstallIn
を追加し、Moduleの指定を削除します。さらにFactoryも削除します。
injectメソッドや、SubcomponentのFactoryメソッドは残したままで大丈夫です。
Contextの依存にアノテーション追加
ModuleなどでContextを依存してる箇所には @ApplicationContext
や @ActivityContext
を付ける必要があります。
@HiltAndroidAppに対応
Applicationクラスを @HiltAndroidApp
に対応します。
これまではDaggerのFactoryでComponentを作ってましたが、 EntryPoints.get
を使ってComponentを取得します。
ここまで設定すればビルドして実行できるようになると思います。Applicationクラスは最後にまた対応します。
Jetpack Hiltの導入
ViewModelやWorkManagerにおいて簡単にDagger対応できるようになります。単純にbuild.gradleに追加するだけなのです。
implementation 'androidx.hilt:hilt-lifecycle-viewmodel:1.0.0-alpha02'
kapt 'androidx.hilt:hilt-compiler:1.0.0-alpha02'
ここまでやっておけば、移行したい画面から徐々に移行することが可能になります。
FeatureモジュールのHilt移行
Subcomponentを使用しているFeatureモジュールをHiltに移行します。
ViewModelの @Inject
を @ViewModelInject
に変更します。
Activityに @AndroidEntryPoint
を追加して、これまで ViewModelProvider.Factory
をInjectしてた箇所を削除します。
あとは @Subcomponent
の定義などが不要になるのですべて削除します。
FragmentのHilt移行の準備
Activityが多くのFragmentを持っている場合、Fragmentを段階的にHilt移行する必要があります。そのための準備としてActivity側を少し修正します。
Activityで使用してるModuleに @InstallIn
を追加します。
Activityを @AndroidEntryPoint
に対応していきます。 DaggerAppCompatActivity
を使うのやめて、代わりに HasAndroidInjector
の対応します。
対象のActivityの @ContributesAndroidInjector
が不要になるので削除します。
ここから先は段階的にFragmentを移行することができます。
FragmentのHilt移行
ViewModelの @Inject
を @ViewModelInject
に変更します。これは大丈夫かと思います。
次に DaggerFragment
をやめて、 @AndroidEntryPoint
を使うようにします。
Hilt対応したので、対象Fragmentの古いDagger設定を削除します。
これでFragmentのHilt移行できます。あとは必要なFragmentに対して段階的に対応していけば良いと思います。
ActivityのHilt移行
Activityで使ってるFragmentの対応がすべて終わったら最後にActivityを移行します。
ViewModelはこれまで同様に @ViewModelInject
を使うようにするだけです。
Activityは既に @AndroidEntryPoint
を使うようにしるので、 単純にHasAndroidInjector
を削除します。
あとは不要になった古い設定を削除します。
ApplicationクラスのHilt移行仕上げ
すべてのActivity/Fragmentの移行が完了したら、Applicationクラスの移行を仕上げます。
DaggerApplicationに関するコードを削除するだけです。
@InstallIn対応
これまでは @InstallIn
をチェックしないようにして、集約してるModuleを作りましたが、これにちゃんと対応します。
まずは各Moduleに @InstallIn
をつけていきます。
すべて付けたら、集約用のModuleを削除します。
さらに、build.gradleに設定していた dagger.hilt.disableModulesHaveInstallInCheck
のフラグも削除します。
不要になったものを削除して仕上げ
色々と不要になったものがあるので、それを削除して完了です!
おつかれさまでした!
Tips
もし、ViewModelが複数の箇所から使用されていて、それが新旧の両方から使用される場合は、 @Inject
と @ViewModelInject
を同時に使えば大丈夫だと思います。