gpt4 book ai didi

android - 如何使用 navGraph 范围初始化 viewModel

转载 作者:行者123 更新时间:2023-12-02 12:09:31 48 4
gpt4 key购买 nike

我开始学习共享 View 模型。
目前我在 Activity 中有 3 个 fragment ,其中 2 个在嵌套的 navGraph 中。

我想为它们创建共享的 navGraph viewModel 范围,但我不明白如何以及在哪里可以在这些 fragment 中初始化 View 模型。

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

private lateinit var viewModel: MainViewModel

然后在 onCreateView里面我像这样初始化 viewModel -
viewModel = ViewModelProvider(this, Factory(requireActivity().application)).get(
MainViewModel::class.java)

如果我想与 2 个 fragment 共享一个 View 模型,如何对 navGraph viewModel 范围执行相同操作?

目前我有这种方法:
private val homeViewModel: HomeViewModel by navGraphViewModels(R.id.nested_navigation)

这是工作,但是

答:我从未在全局变量中看到 viewModel intilazied

B. 我不能用这种方法在工厂内部传递变量

最佳答案

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 在第一次访问时被初始化,所以如果你只输入 homeViewModelonCreateonViewCreated然后它将使用正确的范围创建。
B.)这是事实,您绝对可以使用带有 navGraphViewModels 的自定义工厂,但您真正想要的(可能)是通过使用 SavedStateHandle 将任何 Fragment 参数隐式传递给 ViewModel(请注意,两个 Fragment 的参数中必须有正确的键才能安全工作) .
获取 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 ->
...
}
}

关于android - 如何使用 navGraph 范围初始化 viewModel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61630872/

48 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com