首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用viewModel范围初始化navGraph

如何使用viewModel范围初始化navGraph
EN

Stack Overflow用户
提问于 2020-05-06 08:39:16
回答 1查看 2.3K关注 0票数 6

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

我想为他们两个创建共享的navGraph viewModel作用域,但是我不知道如何在这些片段中初始化视图模型。

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

代码语言:javascript
复制
private lateinit var viewModel: MainViewModel

然后在onCreateView里我会像这样模仿viewModel -

代码语言:javascript
复制
viewModel = ViewModelProvider(this, Factory(requireActivity().application)).get(
   MainViewModel::class.java)

如果我想要与两个片段共享一个视图模型,那么如何对navGraph viewModel作用域进行同样的操作呢?

目前我有这样的方法:

代码语言:javascript
复制
private val homeViewModel: HomeViewModel by navGraphViewModels(R.id.nested_navigation)

这是工作,但是

A.我从来没有在全局变量中看到过viewModel

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

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-05-07 03:28:38

private val homeViewModel: HomeViewModel by navGraphViewModels(R.id.nested_navigation)

这是工作,但是

答:我从未在全局变量中看到viewModel被初始化

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

A.)在本例中,ViewModel是在第一次访问时初始化的,因此,如果您只在onCreateonViewCreated中键入homeViewModel,那么它将被创建为具有正确范围的。

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

要获得SavedStateHandle,需要使用AbstractSavedStateViewModelFactory。要创建一个ViewModel,您必须在onViewCreated中创建您的onCreate (onCreate不能使用导航图),这是使用ViewModelLazy最简单的方法。

要创建viewModelLazy,可以使用createViewModelLazy (tin上的内容)。这可以为您定义一种传递ViewModelStoreOwner (即NavBackStackEntry)和SavedStateRegistryOwner (也就是NavBackStackEntry)的方法。

所以你可以把它放在你的代码中,它应该能工作。

代码语言:javascript
复制
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
        }
    })
}

现在你可以做了

代码语言:javascript
复制
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 ->
        ...
    }
}
票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61630872

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档