如何使用navGraph范围初始化viewModel



我开始学习共享视图模型。目前,我在活动中有3个片段,其中2个在嵌套的navGraph中。

我想为这两个片段创建共享的navGraph视图模型范围,但我不明白如何以及在哪里初始化这些片段中的视图模型。

在我过去的所有应用程序中,我创建了全局视图模型

private lateinit var viewModel: MainViewModel

然后在onCreateView中,我初始化了这样的视图模型-

viewModel = ViewModelProvider(this, Factory(requireActivity().application)).get(
MainViewModel::class.java)

如果我想用两个片段共享一个视图模型,我如何对navGraph视图模型范围进行同样的处理?

目前我有这样的方法:

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是在第一次访问时初始化的,所以如果您只在onCreateonViewCreated中键入homeViewModel,那么它将使用正确的作用域创建。

B.(事实上,您肯定可以使用带有navGraphViewModels的自定义工厂,但您真正想要的(可能(是通过使用SavedStateHandle将任何Fragment参数隐式传递给ViewModel(注意,两个片段的参数中都必须有正确的键才能安全工作(。

要获得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 ->
...
}
}

相关内容

  • 没有找到相关文章

最新更新