使用导航组件时从子级获取父片段 [英] Get parent fragment from child when using Navigation Component

查看:23
本文介绍了使用导航组件时从子级获取父片段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I need to transfer data from one fragment to another. Now the recommended way to do this is to use a shared ViewModel. To get the same instance available in both fragments, common owner is needed. As it can be their common Activity. But with this approach (In the case of Single Activity), the ViewModel instance will live throughout the entire application. In the classic use of fragments, you can specify ViewModelProvider (this) in the parent fragment, and ViewModelProvider (getParentFramgent ()) in the child. Thus, the scope of ViewModel is limited to the life of the parent fragment. The problem is that when using Navigation Component, getParentFramgent () will return NavHostFragment, not the parent fragment. What do I need to do?

代码示例:

navigation_graph.xml 中的某处:

Somewhere in 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(从 getParentFragment() 返回)作为所有片段的公共,但是,就像 Activity, ViewModel.onCleared() 在真正的父片段完成时不会被调用.

I can use NavHostFragment(returned from getParentFragment()) as a common for all fragments, but then, as in the case of Activity, ViewModel.onCleared() will not be called when the real parent fragment finishes.

推荐答案

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

There's really no way to do this.

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

Here is a code snippet from 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()中.

Under the hood, the FragmentManager is used, which calls replace(). Therefore, the child fragment is not added, but is replaced with a new one, so it will not be in getParentFramgent().

这篇关于使用导航组件时从子级获取父片段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆