How to check if a ViewModel already exists for a given ViewModelProvider

Viewed 384

This video (MVVM & Nested Fragments/Views: ViewModel Contracts - By Marcos Paulo Damesceno, Bret Erickson droidcon San Francisco 2019 ) shows a way to deal with communication between activities/fragments using ViewModel.

I am implementing it for learning purpose but I got stuck.

// 18:35 of the video

private const val VM_KEY = "view_model_contract_key"

fun <T> Fragment.viewModelContracts() = lazy {
    val clazz: Class<ViewModel> = arguments?.getSerializable(VM_KEY) as Class<ViewModel>
    val viewModelProvider = ViewModelProvider(requireActivity())

    return@lazy viewModelProvider.get(clazz) as T
}

The ViewModelStoreOwner passed as parameter is an Activity, but if I have a Fragment inside another Fragment where both of them share the same ViewModel, the ViewModel returned by viewModelContracts() will be a different object as the one created by the Parent Fragment.

interface ChildViewModelContract {
    // ...
}

class SomeViewModel : ViewModel(), ChildViewModelContract {
    // ...
}

class ParentFragment: Fragment {
    private val viewModel: SomeViewModel by viewModels()

    // ...
}

class ChildFragment: Fragment {
    private val viewModelContract: ChildViewModelContract by viewModelContracts()

    // ...
}

The ideal solution would be to check in fun <T> Fragment.viewModelContracts() if the ViewModelProvider of the parent fragment has the ViewModel stored in it, and if not, use the ViewModelProvider of the Activity. But I'm not knowing how to do this.

fun <T> Fragment.viewModelContracts() = lazy {
    val clazz: Class<ViewModel> = arguments?.getSerializable(VM_KEY) as Class<ViewModel>
    
    val parentFragment = parentFragment
    if (parentFragment != null) {
        val viewModelProvider = ViewModelProvider(parentFragment)
        // is there any way to do something like this?
        if (viewModelProvider.isViewModelStored(clazz)) {
            return@lazy viewModelProvider.get(clazz) as T 
        }
    }
    
    val viewModelProvider = ViewModelProvider(requireActivity())
    
    return@lazy viewModelProvider.get(clazz) as T
}
0 Answers
Related