Navigation Architecture Component- Passing argument data to the startDestination
Solution 1:
TLDR: You have to manually inflate the graph, add the keys/values to the defaultArgs, and set the graph on the navController
.
Step 1
The documentation tells you to set the graph in the <fragment>
tag in your Activity
's layout. Something like:
<fragment
android:id="@+id/navFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:graph="@navigation/nav_whatever"
app:defaultNavHost="true"
/>
REMOVE the line setting the graph=
.
Step 2
In the Activity that will be displaying your NavHostFragment
, inflate the graph like so:
val navHostFragment = navFragment as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.nav_whatever)
Where navFragment
is the id you gave your fragment in XML, as above.
Step 3 [Crucial!]
Create a bundle to hold the arguments you want to pass to your startDestination
fragment and add it to the graph's default arguments:
val bundle = Bundle()
// ...add keys and values
graph.addDefaultArguments(bundle)
Step 4
Set the graph on the host's navController
:
navHostFragment.navController.graph = graph
Solution 2:
OK, I found a solution to that problem thanks to Ian Lake from the Google team. Let say you have an activity A that will start activity B with some intent data and you want to get that data in the startDestination you have two options here if you using safe args which is my case you could do
StartFragmentArgs.fromBundle(requireActivity().intent?.extras)
to read the args from the Intent. If you don't use safe args you can extract the data from the bundle your self-using requireActivity().intent?.extras
which will return a Bundle you can use instead of the fragment getArguments()
method. That's it I try it and everything works fine.
Solution 3:
It had been fixed in 1.0.0-alpha07
. See detail.
The solution is similar to Elliot Schrock's answer, but wrapping by official API.
We have to manually inflate NavHostFragment
or graph
Use
NavHostFragment.create(R.navigation.graph, args)
Or
navController.setGraph(R.navigation.graph, args)
The args are the data we want to pass to start destination.
Solution 4:
I think this has changed again with the 1.0.0 release. And Google has hidden this information very well in the official documentation. Or at least I struggled to find it, but stumbled upon it in the Migrate to the Navigation component guide. How to pass arguments to the start destination is mentioned here: Pass activity destination args to a start destination fragment
In short
- You have to set the navigation graph programatically:
findNavController(R.id.main_content)
.setGraph(R.navigation.product_detail_graph, intent.extras)
- Don't set the graph in the NavHostFragment XML declaration.
- Read the extras from the receiver side:
val args by navArgs<ProductDetailsArgs>()
val productId = args.productId
Update: Google has said that the official documentation for passing arguments to the initial navigation target is indeed missing. Hopefully this is added soon as part of the Navigation component documentation.
Solution 5:
Following Pass data to the start destination section from official doc:
First, construct a Bundle that holds the data:
val bundle = Bundle().apply {
putString(KEY, "value")
}
Next, use one of the following methods to pass the Bundle to the start destination:
-
If you're creating your NavHost programmatically
NavHostFragment.create(R.navigation.graph, bundle)
-
Otherwise, you can set start destination arguments by calling one of the following overloads of
NavController.setGraph()
:navHostFragment.navController.setGraph(R.navigation.graph, bundle)
Then you should use Fragment.getArguments()
to retrieve the data in your start destination.
EDIT:
You can also use FragmentArgs
instead of creating a bundle manually which makes it more convenient and type safe:
navHostFragment.navController.setGraph(R.navigation.graph, MyFragmentArgs(arg).toBundle())
Then in the fragment you can retrieve args as:
private val args: PodFragmentArgs by navArgs()
Make sure your fragment has argument element in the navigation.xml file:
<fragment
android:id="@+id/myFragment"
android:name="MyFragment"
android:label="fragment_my"
tools:layout="@layout/fragment_my">
<argument
android:name="argName"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
</fragment>