10

我正在使用 Android Jetpack (2.2.0-alpha01) 的导航组件。

我希望使用一个嵌套在我的主 NavHostFragment 内的子 NavHostFragment,它配备了自己的子导航图。请查看下图了解上下文:

在此处输入图像描述

子导航主机在 MainNavHost 堆栈前面的片段中定义如下:

<fragment
    android:id="@+id/childNavHostFragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="false"
    app:navGraph="@navigation/child_graph" />

在 CHILD Nav Host Fragment 前面的片段中,我正在尝试使用以下代码获取范围为 R.navigation.child_graph 的 ViewModel:

private val childGraphScopedViewModel: ChildGraphScopedViewModel by navGraphViewModels(R.navigation.child_graph) {
    viewModelFactory
}

访问 childGraphScopedViewModel 时,我遇到了崩溃并显示错误消息:

java.lang.IllegalArgumentException: No NavGraph with ID 2131689472 is on the NavController's back stack.

我相信惰性初始化调用by navGraphViewModel()正在寻找 mainGraph 中的导航图。

如何访问子 navHostFragment 范围的 ViewModel?感谢您的时间。

4

3 回答 3

10

这对我有用,无需定义自定义ViewModelProvider(2.2.0):

private val viewModel: ChildGraphScopedViewModel by navGraphViewModels(R.id. child_graph)

一个容易犯的错误是使用R.navigation.child_graph(坏)而不是R.id.child_graph(好)

于 2020-04-01T14:39:52.190 回答
5

您可以通过提供 child 的 viewModelStore 来做到这一点NavController

override fun onViewCreated(
     view: View, 
     savedInstanceState: Bundle?
) {
    super.onViewCreated(view, savedInstanceState)

    val childHostFragment = childFragmentManager
          .findFragmentById(R.id.childNavHostFragment) as NavHostFragment

    val childNavController = childHostFragment.navController

    val childViewModel: ChildGraphScopedViewModel = ViewModelProvider(
         childNavController.getViewModelStoreOwner(R.navigation.child_graph)
    ).get(ChildGraphScopedViewModel::class.java)
}

我写了一个 Kotlin 扩展来使它更容易

inline fun <reified T: ViewModel> NavController.viewModel(@NavigationRes navGraphId: Int): T {
    val storeOwner = getViewModelStoreOwner(navGraphId)
    return ViewModelProvider(storeOwner)[T::class.java]
}

用法

val viewModel = findNavController().viewModel(R.navigation.nav)
于 2019-09-04T10:01:14.717 回答
3

由于某种原因,创建导航图并将include其嵌套在主导航图中对我不起作用。可能这是一个错误。

您可以选择导航图中需要组合在一起的所有片段,然后right-click->move to nested graph->new graph

现在这会将选定的片段移动到主导航图中的嵌套图,如下所示:

<navigation app:startDestination="@id/homeFragment" ...>
    <fragment android:id="@+id/homeFragment" .../>
    <fragment android:id="@+id/productListFragment" .../>
    <fragment android:id="@+id/productFragment" .../>
    <fragment android:id="@+id/bargainFragment" .../>

    <navigation 
        android:id="@+id/checkout_graph" 
        app:startDestination="@id/cartFragment">

        <fragment android:id="@+id/orderSummaryFragment".../>
        <fragment android:id="@+id/addressFragment" .../>
        <fragment android:id="@+id/paymentFragment" .../>
        <fragment android:id="@+id/cartFragment" .../>

    </navigation>

</navigation>

现在,在初始化 ViewModel 时在片段内部执行此操作

val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph)

如果您需要传递视图模型工厂(可能用于注入视图模型),您可以这样做:

val viewModel: CheckoutViewModel by navGraphViewModels(R.id.checkout_graph) { viewModelFactory }
于 2020-05-21T07:53:01.123 回答