Получить родительский фрагмент из дочернего, когда используется Navigation Component

Нужно передать данные из одного фрагмента в другой. Сейчас рекомендуемый способ это сделать - использовать общий ViewModel. Чтобы один и тот же экземпляр был доступен в обоих фрагментах нужен какой-то общий owner. В качестве него может выступать их общая Activity. Но при таком подходе(В случае Single Activity), экземпляр ViewModel будет жить на всём протяжении работы приложения. При классическом использовании фрагментов, можно указать ViewModelProvider(this) в родительском фрагменте, и ViewModelProvider(getParentFramgent()) в дочернем. Таким образом scope ViewModel'a ограничится жизнью родительского фрагмента. Проблема в том, что при использовании Navigation Component getParentFramgent() будет возвращать NavHostFragment,а не родительский фрагмент. Как быть, собственно?

Фрагменты кода:

Навигационный граф:

 <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) {
            //Так не работает
            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
                        )
                    }
        }

Ответы (1 шт):

Автор решения: Ziens

На самом деле никак.

Вот фрагмент кода из 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(). Поэтому дочерний фрагмент не добавляется, а замещается новым, следовательно его и не будет в getParentFramgent().

→ Ссылка