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?
Code samples:
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>
Somewhere in 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
)
}
}
EDIT:
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.