androidandroid-navigationandroid-jetpack-navigationandroid-navigation-graph

Pass arguments safely to nested graph with Navigation Component


I'm using Android Jetpack Navigation Component. I have a nested nav graph with id, say R.id.nested_graph The first Fragment of the nested graph receives one parameter.

<navigation
        android:id="@+id/nested_graph"
        android:label="Nested Graph"
        app:startDestination="@id/firstFragment">
        <fragment
            android:id="@+id/firstFragment"
            android:name="...."
            android:label="....">
            <argument
                android:name="item_id"
                app:argType="integer" />
        </fragment>
        [...]
    </navigation>

How can I pass the parameter to the nested graph using safe args?

At the moment, I need to pass the argument manually in the bundle, using the API that receives the id of the nested graph directly:

        val args = Bundle()
        args.putInt("item_id", itemId)
        navController.navigate(R.id.nested_graph, args)

I'd like to use safe args, and do something like:

        val directions = OrigininFragmentDirections.nestedGraph(itemId)
        navController.navigate(directions)

But when trying that, I get the following error at build time:

Too many arguments for public final fun nestedGraph(): NavDirections defined 

The issue is that the nav graph preprocessing is generating the factory method to create the NavDirections object without the required parameter in the signature.

The declaration of the nested graph looks like this:


Solution

  • After some trial and error experimentation (I don't think it's officially documented by Google, or at least I could not find it), I've discovered that navigating to nested nav graphs passing arguments safely can be done:

    You need to add the argument XML object the first fragment expects in the root of the nested fragment itself.

    In my case, the fragment with id firstFragment, which is the first fragment in the nested graph receives:

                <argument
                    android:name="item_id"
                    app:argType="integer" />
    

    Hence, I need to add that argument to the nested graph:

    <navigation
            android:id="@+id/nested_graph"
            android:label="Nested Graph"
            app:startDestination="@id/firstFragment">
    
                <argument
                    android:name="item_id"
                    app:argType="integer" />
    
            <fragment
                android:id="@+id/firstFragment"
                android:name="...."
                android:label="....">
                <argument
                    android:name="item_id"
                    app:argType="integer" />
            </fragment>
            [...]
        </navigation>
    

    Now I can navigate to it with:

       val directions = OrigininFragmentDirections.nestedGraph(itemId)
            navController.navigate(directions)
    

    Note that the navigation graph editor does not do it for you. This needs to be done manually in the XML code.