我开始学习共享视图模型。目前,我在活动中有3个片段,其中2个片段在嵌套的navGraph中。
我想为它们两个创建共享的navGraph viewModel范围,但是我不明白如何以及在何处可以在这些片段中初始化视图模型。
在过去的所有应用程序中,我都创建了全局视图模型
private lateinit var viewModel: MainViewModel
然后在onCreateView
中,我像这样初始化viewModel-
viewModel = ViewModelProvider(this, Factory(requireActivity().application)).get(
MainViewModel::class.java)
如果要与两个片段共享一个视图模型,如何对navGraph viewModel范围执行相同操作?
目前,我有这种方法:
private val homeViewModel: HomeViewModel by navGraphViewModels(R.id.nested_navigation)
并且可以,但是
A。我从未在全局变量中看到过viewModel正确的声音
B。我无法通过这种方法在工厂内部传递变量
private val homeViewModel: HomeViewModel by navGraphViewModels(R.id.nested_navigation)
并且可以,但是
A。我从未在全局变量中看到过viewModel初始化]
B。我无法使用这种方法在工厂内部传递变量
A。]在这种情况下,ViewModel会在首次访问时初始化,因此,如果仅在
homeViewModel
或onCreate
中键入onViewCreated
,则会在正确的范围内创建它。
B。)这是事实,您可以在navGraphViewModels
中使用自定义工厂,但是您真正想要的(可能)是隐式地将任何Fragment参数传递给ViewModel(请注意,您的两个片段都必须可以使用SavedStateHandle
在其参数中使用正确的键,以使其安全地工作)。
要获得SavedStateHandle
,您需要使用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> { // Wrapped in lazy to not search the NavController each time we want the backStackEntry 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 -> ... } }