4
Help us understand the problem. What are the problem?

posted at

updated at

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

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 }
    )
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
4
Help us understand the problem. What are the problem?