LoginSignup
5
4

More than 1 year has passed since last update.

NavGraphで共有するViewModelでAssisted Injectをする

Last updated at Posted at 2021-11-16

NavGraphのidで共有しているViewModelをAssistedInjectで生成したく、なおかつ今まで通り別フラグメントに共有したい要件がある際の解決方法を、どこにも記事がなかったため備忘録として残します。

今回は該当箇所のみを扱い、Dagger-Hiltの導入方法などは説明しません。

Hilt導入の公式ドキュメント ->
https://dagger.dev/hilt/gradle-setup

動作環境

  • Dagger-Hilt 2.39
  • Navigation 2.3.0

前提

AssistedInjectを楽にするためにFragmentの拡張関数としてtakahiromさんの記事を参考に作成しています。
ステップバイステップでDaggerを使った引数ありのViewModelの初期化を理解する

assistedViewModels
inline fun <reified T : ViewModel> Fragment.assistedViewModels(
    owner: ViewModelStoreOwner = this,
    crossinline body: () -> T
): Lazy<T> {
    return viewModels({ owner }) {
        object : ViewModelProvider.AndroidViewModelFactory(this.requireActivity().application) {
            override fun <T : ViewModel?> create(modelClass: Class<T>): T {
                @Suppress("UNCHECKED_CAST")
                return body() as T
            }
        }
    }
}

結論

findNavController().getViewModelStoreOwner(R.id.exampleGraphId)をViewModelStoreOwnerとし、親FragmentでAssistedInject、子Fragmentでは今まで通りViewModelProviderでStoreOwnerを上記のfindNav~ としてViewModelを取得する。

ViewModel

SampleViewModel.kt
class SampleViewModel @AssistedInject constructor(
    @Assisted private val sampleId: String,
    private val sampleRepository: SampleRepository
) : ViewModel() {

    @AssistedFactory
    interface Factory {
        fun create(sampleId: String): SampleViewModel
    }
}

親Fragment

ParentFragment.kt
class ParentFragment: Fragment() {
    private val args: ParentFragmentArgs by navArgs()

    @Inject
    lateinit var viewModelFactory: SampleViewModel.Factory

    // ここが肝(わかりやすいように変数で切ってます)
    val owner: ViewModelStoreOwner = findNavController().getViewModelStoreOwner(R.id.exampleGraphId)

    private val sampleViewModel: SampleViewModel by assistedViewModels(owner) {
        viewModelFactory.create(args.sampleId)
    }

子Fragment

ChildFragment.kt
class ChildFragment: Fragment() {
    // ここが肝(ParentFragmentで指定したOwnerと一緒のものを指定する)
    val owner: ViewModelStoreOwner = findNavController().getViewModelStoreOwner(R.id.exampleGraphId)

    private val sharedViewModel: SampleViewModel by viewModels(
        ownerProducer = { owner }
    )
5
4
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
5
4