使用导航组件时从子级获取父片段 [英] Get parent fragment from child when using Navigation Component
问题描述
我需要将数据从一个片段传输到另一个片段.现在推荐的方法是使用共享的 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屋!