I have an activity A that start activity B passing to it some intent data. Activity B host a navigation graph from the new Navigation Architecture Component.I want to pass t
So finally, I have found a solution to this issue.
At the time of writing this answer, I am using Navigation 2.2.0-alpha01
If you want to pass some data to the start destination directly as arguments from host activity, you need to manually set your host’s navigation graph inside the host activity’s onCreate() method, as shown below:
Get you navController:
val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
Then in the host activity's onCreate()
val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
Or if you want to pass the whole intent extras as it is to the startDestination:
navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
Since intent.extras
would return a Bundle
only
When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in the NavHostFragment definition, because doing so results in inflating and setting the navigation graph twice.
While reading these arguments in your startDestination fragment:
If you are using the Safe Args Plugin (which is very much recommended), then in your fragment:
private val args by navArgs<DummyFragmentArgs>()
Safe Args plugin would generate an Args class by appending Args to your fragment name. For example, if you fragment is called DummyFragment
then Safe Args would generate a class called DummyFragmentArgs
where navArgs<>
is an extension function defined in Android KTX
If you are not using Android KTX, you can get the args object like:
val args = DummyFragmentArgs.fromBundle(arguments!!)
Once you've acquired the arguments object, you can simply fetch your arguments:
args.someArgument
Notice how we passed "some_argument"
as argument, and we are reading it as someArgument
using Safe Args
If you are not using Safe Args (there is no reason to not use it though), you can access your arguments like this:
arguments?.getString("some_argument")
All of this is documented in Migrate to Navigation Component documentation here: https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment
So for the people Still struggling with this. I found another way to do this without using Safe-Args and a step using @Elliot's Answer.
So lets say you received some arguments in Activity B from Activity A and Your Activity B has a fragment startDestination you are initialising the Nav controller like this:
navController = Navigation.findNavController(this, R.id.detailFragment);
from the Nav Controller you will have access to your graph which you have set in the XML like this and you can set the arguments in the defaultArguments:
navController.getGraph().addDefaultArguments(extras);
Note: This will also update values of the keys if it is already present in the graph xml
Now in your Fragment you have to find the default arguments from your NavHostFragment like this:
Bundle defaultArguments = NavHostFragment.findNavController(this).getGraph().getDefaultArguments();
and you will have the values there. I don't know why @Elliot thinks it's crucial but it should be the way?
UPDATE alpha09: addDefault argument is no longer supported in this version, You have to use NavArgument
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.
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>
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:
https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment
In short
findNavController(R.id.main_content) .setGraph(R.navigation.product_detail_graph, intent.extras)
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.
addDefaultArguments is no more in the latest versions of library. I have fixed the problem like this:
val navHostFragment = fragment_navigation_onboarding as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph:NavGraph = navInflater.inflate(R.navigation.navigation_your_xml)
val model = Model()//you might get it from another activity
graph.addArgument("Data", NavArgument.Builder().setDefaultValue(model).build()) // This is where you pass the bundle data from Activity to StartDestination
navHostFragment.navController.graph = graph