Dagger AndroidからHiltに段階的に移行する

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 を同時に使えば大丈夫だと思います。

参考

Written by

Programmer / Gamer / Google Developers Expert for Android, Kotlin / @STAR_ZERO

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store