android - 使用导航组件时从子级获取父级片段
问题描述
我需要将数据从一个片段传输到另一个片段。现在推荐的方法是使用共享的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()
) 作为所有片段的公用,但是,在 的情况下Activity
,ViewModel.onCleared()
当真正的父片段完成时不会被调用。
解决方案
真的没有办法做到这一点。
这是来自的代码片段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()
.
推荐阅读
- kubernetes - 如何在 configMap 中获取环境变量
- java - 使用 md5 消息摘要和 DESede/CBC/PKCS5Padding 将用于 3DES 加密的 java 代码转换为 python
- docker - 拉取源代码并在 docker 镜像中使用的最佳实践
- python - Python3 - 如何使用 for 循环遍历列表中的第一个和最后 10 个项目?
- openpyxl - Python openpyxl 维度在行和列中多了一个
- laravel - Laravel 权限仍然允许我访问页面
- javascript - 限制输入只接受括号,而不是字母或数字
- jmeter - Jmeter 在服务器日志中找不到 200 个用户负载测试时抛出“SocketException:连接重置”错误
- reactjs - Material-UI 自动完成 endAdornment 问题
- java - 初始化 ArrayList 引发的 NullPointerException