ViewModelでAssistedInjectを使う

Dagger 2.31より、AssistedInjectのサポートが入りました。このAssistedInjectをViewModelで使用する方法です。

Kenji Abe
Jan 17, 2021

追記: この方法には問題があります。SavedStateHandleを使うようにしましょう。

画面の引数などをDaggerのInjectと組み合わせて、ViewModelのコンストラクタに渡したい場合があったりします。
こういったケースではAssistedInjectを使うことで可能になります。
(他には SavedStateHandle を使う方法もあります。)

build.gradle

2.31のHiltを使っていきます。

ViewModel

以下のようなコンストラクタを持つViewModelを例にします。

1つ目は通常のDaggerモジュールなどに定義されたオブジェクトで、2つ目で SavedStateHandle も受け取るようにします。最後に画面から渡したい引数になります。

今回は SavedStateHandle も使ってますが、不要なら無くても大丈夫です。

AssistedFactory

画面から渡したいものを AssistedFactory として定義します。

画面からコンストラクタに渡したいものを引数にして、Injectしたいクラスが戻り値になってるメソッドを定義したinterfaceを作ります。

interfaceには @AssistedFactoryのアノテーションを追加します。

ViewModelFactory

次にViewModelFactoryを定義しておきます。

今回は SavedStateHandle も使ってるので AbstractSavedStateViewModelFactory を使っています。もし不要なら ViewModelProvider.Factory も使えます。

ViewModelのインスタンスは AssistedFactory のメソッドから作成して返します。

AssistedInject

コンストラクタを AssistedInject の設定をします。

AssistedInjectしたい引数に @Assisted を追加します。
ただし、通常のモジュールからInjectするものは無くて大丈夫です。

コンストラクタには @Inject の代わりに @AssistedInject を追加します。

画面から値を渡す

最後に画面から値を渡すようにします。

先程作った AssistedFactory をInjectするようにして、それをViewModelFactoryで使用する感じになります。

ちょっとややこしそうに見えますが、一度やってみるとそこまで難しくはないと思います。

注意点

AssistedFactory と AssistedInject のパラメーターの引数の順番は一致している必要があります。

AssistedInject においては引数の順番が重要になってきます。これは意図しないバグに繋がる可能性もあるので注意してください。

参考

ちょっと前のやり方

--

--

Kenji Abe

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