首页 > 解决方案 > 使用导航组件时从子级获取父级片段

问题描述

我需要将数据从一个片段传输到另一个片段。现在推荐的方法是使用共享的ViewModel. 要在两个片段中获得相同的实例,需要共同的所有者。因为它可以是他们的共同点Activity。但是使用这种方法(在 Single Activity 的情况下),ViewModel实例将存在于整个应用程序中。在经典片段的使用中,您可以ViewModelProvider (this)在父片段中指定,并ViewModelProvider (getParentFramgent ())在子片段中指定。因此,范围ViewModel仅限于父片段的生命周期。问题是使用导航组件时,getParentFramgent ()将返回 NavHostFragment,而不是父片段。我需要做什么?

代码示例

在 navigation_graph.xml 中的某处:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/nav"
        app:startDestination="@id/mainMenuFragment">

    <fragment
        android:id="@+id/mainMenuFragment"
        android:name="com.mypackage.mainmenu.MainMenuFragment"
        android:label="MainMenu"
        tools:layout="@layout/fragment_main_menu">

        <action
            android:id="@+id/start_game_fragment"
            app:destination="@id/gameNav" />

    </fragment>

    <navigation
        android:id="@+id/gameNav"
        app:startDestination="@id/gameFragment">

        <fragment
            android:id="@+id/gameFragment"
            android:name="com.mypackage.game.GameFragment"
            android:label="@string/app_name"
            tools:layout="@layout/fragment_game"/>
    </navigation>

</navigation>

在某处MainMenuFragment

    override fun startGame(gameSession: GameSession) {
            //This approach doesn't work
            ViewModelProvider(this)[GameSessionViewModel::class.java].setGameSession(
                gameSession
            )
            findNavController().navigate(R.id.start_game_fragment)
    }

GameFragment

    override fun onActivityCreated(savedInstanceState: Bundle?) {
            super.onActivityCreated(savedInstanceState)
            gameSessionViewModel =
                ViewModelProvider(requireParentFragment())[GameSessionViewModel::class.java].apply {
                    val session = gameSession.value
                    )
                }
    }

编辑:

我可以使用NavHostFragment(returned from getParentFragment()) 作为所有片段的公用,但是,在 的情况下ActivityViewModel.onCleared()当真正的父片段完成时不会被调用。

标签: androidandroid-fragmentsandroid-viewmodel

解决方案


真的没有办法做到这一点。

这是来自的代码片段androidx.navigation.fragment.FragmentNavigator

public NavDestination navigate(@NonNull Destination destination, @Nullable Bundle args,
                    @Nullable NavOptions navOptions, @Nullable Navigator.Extras navigatorExtras) {
    // ...
    final FragmentTransaction ft = mFragmentManager.beginTransaction();
    // ...
    ft.replace(mContainerId, frag);
    ft.setPrimaryNavigationFragment(frag);
    // ...
}

在引擎盖下,FragmentManager使用的是 ,它调用replace(). 因此,子fragment没有被添加,而是被一个新的替换,所以它不会在getParentFramgent().


推荐阅读