Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

like image 431
GaRRaPeTa Avatar asked Dec 18 '19 12:12

GaRRaPeTa


2 Answers

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.

like image 96
GaRRaPeTa Avatar answered Oct 20 '22 07:10

GaRRaPeTa


@GaRRaPeTa answer is almost correct, but if you navigate from main graph to nested graph by action using SafeArgs, you must also add an argument to the action:

<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/graph_main"
    app:startDestination="@id/mainFragment">

    <fragment
        android:id="@+id/mainFragment"
        android:name="com.example.MainFragment">

        <action
            android:id="@+id/toNestedGraph"
            app:destination="@id/graph_nested">

            <argument
                android:name="arg_name"
                app:argType="string" />
        </action>
    </fragment>

</navigation>
like image 9
Alektas Avatar answered Oct 20 '22 06:10

Alektas