private val homeViewModel: HomeViewModel by navGraphViewModels(R.id.nested_navigation)
And It's work, but
A. I never saw viewModel initialized right in the global variable
B. I can't pass variables inside factory with this approach
A.) 在这种情况下,ViewModel在第一次访问时被初始化,因此如果您只是在onCreate
或onViewCreated
中输入homeViewModel
,那么它将在正确的范围内创建。
B.) 这是正确的,你确实可以使用navGraphViewModels
和自定义工厂,但你真正想要的(可能)是通过使用SavedStateHandle
来隐式传递Fragment参数到ViewModel(请注意,两个Fragment必须在其参数中具有正确的键才能安全地使用此方法),为了获得SavedStateHandle
,您需要使用AbstractSavedStateViewModelFactory
。要创建一个AbstractSavedStateViewModelFactory
,您必须在onViewCreated
中创建ViewModel(onCreate
在导航图中不起作用),最简单的方法是使用ViewModelLazy
。
要创建viewModelLazy
,可以使用createViewModelLazy
(它所说的就是)。这可以定义一种方式,使您可以传递ViewModelStoreOwner
(即NavBackStackEntry
)和SavedStateRegistryOwner
(也是NavBackStackEntry
)。
因此,您可以将此代码放入您的代码中,它应该可以工作。
inline fun <reified T : ViewModel> SavedStateRegistryOwner.createAbstractSavedStateViewModelFactory(
arguments: Bundle,
crossinline creator: (SavedStateHandle) -> T
): ViewModelProvider.Factory {
return object : AbstractSavedStateViewModelFactory(this, arguments) {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel?> create(
key: String, modelClass: Class<T>, handle: SavedStateHandle
): T = creator(handle) as T
}
}
inline fun <reified T : ViewModel> Fragment.navGraphSavedStateViewModels(
@IdRes navGraphId: Int,
crossinline creator: (SavedStateHandle) -> T
): Lazy<T> {
val backStackEntry by lazy { findNavController().getBackStackEntry(navGraphId) }
return createViewModelLazy(T::class, storeProducer = {
backStackEntry.viewModelStore
}, factoryProducer = {
backStackEntry.createAbstractSavedStateViewModelFactory(
arguments = backStackEntry.arguments ?: Bundle(), creator = creator
)
})
}
inline fun <reified T : ViewModel> Fragment.fragmentSavedStateViewModels(
crossinline creator: (SavedStateHandle) -> T
): Lazy<T> {
return createViewModelLazy(T::class, storeProducer = {
viewModelStore
}, factoryProducer = {
createAbstractSavedStateViewModelFactory(arguments ?: Bundle(), creator)
})
}
@Suppress("UNCHECKED_CAST")
inline fun <reified T : ViewModel> Fragment.fragmentViewModels(
crossinline creator: () -> T
): Lazy<T> {
return createViewModelLazy(T::class, storeProducer = {
viewModelStore
}, factoryProducer = {
object : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(
modelClass: Class<T>
): T = creator.invoke() as T
}
})
}
现在您可以执行以下操作
private val homeViewModel: HomeViewModel by navGraphSavedStateViewModels(R.id.nested_navigation) { savedStateHandle ->
HomeViewModel(savedStateHandle)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view)
homeViewModel.someData.observe(viewLifecycleOwner) { someData ->
...
}
}