41

How does one pass argument(s) to a nested Navigation architecture component graph?

Let's say I construct my navigation graph to navigate from FragmentA --> Nested, where Nested contains FragmentB --> FragmentC...

If this was a pure FragmentA --> FragmentB... graph, I would just set up the navigation with FragmentADirections.actionFragmentAToFragmentB(argument = foo). But that action takes zero arguments as soon as you turn B --> C into Nested...

So what am I supposed to do?

4 Answers 4

107

Global actions might be a way but I didn't get that working as I wanted once I extracted the nested graph to its own .xml. But it turned out to be embarrassing simple - just add the arguments manually in code, to your action.

An example related to the question would be:

Save the nested graph to nested_graph.xml, it will look something like

<navigation
    android:id="@+id/nested_graph"
    app:startDestination="@id/fragmentB"
    ...>

    <fragment 
        android:id="@+id/fragmentB"
        ...>
        <argument
            android:name="foo"
            app:argType="integer"/>
        <action 
            ... // navigation action to FragmentC />
    </fragment>

    <fragment ...  // FragmentC stuff
</navigation>

To pass arguments to nested_graph.xml from a different graph, say root_graph.xml do

<navigation
    android:id="@+id/root_graph"
    app:startDestination="@id/fragmentA"
    ...>

    <fragment 
        android:id="@+id/fragmentA"
        ... >
        <action
            android:id="@+id/action_fragmentA_to_nested_graph"
            app:destination="@id/nested_graph">
            <argument
                android:name="foo"
                app:argType="integer"/>
        </action>
    </fragment>
    <include app:graph="@navigation/nested_graph"/>
</navigation>

In other words, just add the same <argument ... /> to the root_graph action as you expect to receive in the nested_graph.

Sign up to request clarification or add additional context in comments.

7 Comments

Agreed this seems like the only workaround for now. There is a feature request for improving this: issuetracker.google.com/issues/109505019
embaressingly easy :)) they are the ones to be embraced that disabled it in attributes editor window :/
Is there a logical reason this functionality wouldn't be documented/or available in the nav editor? What I mean is, is it assumed we would instead store the values that need to be passed in a shared view model or something like that? It seems awkward that we need a SO post to explain this simple functionality.
Thanks for this, however does safeargs work with this? I'm not able to find a generated class holding the args.
@ZachSperske It sure does. I guess you will have to debug a bit more :)
|
1

First Approach:

  1. In Included Graph inside of the <fragment> block of IncludedFragment add the destination to the @id/included_fragment(itself):
<action
    android:id="@+id/open_included_fragment"
    app:destination="@+id/included_fragment"/>
  1. In the Main Graph make sure that your desired <action> id is the same as the id of the <action> in Included Graph.

Overall your code should be like this:

Main Graph

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main_graph"
    app:startDestination="@+id/main_fragment">
    
    <include app:graph="@navigation/included_graph"/>

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

        <action
            android:id="@+id/open_included_fragment"
            app:destination="@+id/included_graph"/>
    </fragment>

</navigation>

Included Graph

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/included_graph"
    app:startDestination="@+id/included_fragment">
    
    <fragment
        android:id="@+id/included_fragment"
        android:name="com......IncludedFragment">

        <action
            android:id="@+id/open_included_fragment"
            app:destination="+@id/included_fragment"/>

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

</navigation>

Then, to navigate to the IncludedFragment, you should use IncludedFragmentDirections class:

findNavController().navigate(
    IncludedFragmentDirections.openIncludedFragment(69)
)

Second Approach:

  1. Use the same Main Graph navigation graph XML as in the First Approach.
  2. Included Graph should be like this:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/included_graph"
    app:startDestination="@+id/included_fragment">
    
    <fragment
        android:id="@+id/included_fragment"
        android:name="com......IncludedFragment">

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

</navigation>
  1. Create an extended NavDirections class to allow the passing of the arguments (because the default generated one is ActionOnlyNavDirections without arguments):
class ActionArgumentsNavDirections(
    override val actionId: Int,
    override val arguments: Bundle
) : NavDirections
  1. Use ActionArgumentsNavDirections in the navigation method, where actionId equals to R.id.open_included_fragment, and arguments should be initialized with the help of IncludedFragmentArgs class, like this:
findNavController().navigate(
    ActionArgumentsNavDirections(
        actionId = R.id.open_included_fragment,
        arguments = IncludedFragmentArgs(69).toBundle()
    )
)

Comments

0

actully it's very simple you just need to add your arguments in nested_nav for example

 <navigation
        android:id="@+id/root_graph"
        app:startDestination="@id/fragmentA"
            ...>

            <fragment
                android:id="@+id/fragmentA"
            ... >
            <action
                android:id="@+id/action_fragmentA_to_nested_graph"
                app:destination="@id/nested_graph">
            </action>
        </fragment>
        <navigation
            android:id="@+id/nested_graph"
            app:startDestination="@id/fragmentB"
                ...>
            <argument
                android:name="foo"
                app:argType="integer"/>
            <fragment
            android:id="@+id/fragmentB"
                ...>
            <argument
            android:name="foo"
            app:argType="integer"/>
            <action
                ... // navigation action to FragmentC />
                </fragment>
            
            <fragment ...  // FragmentC stuff
        </navigation>
    </navigation>

or you can send your data with a bundle

Comments

-1

If you do not want to create a separated xml for the nested graph you can override destination argument in an action as android developers says here. I just test it for use with navigation graph view model scope and it worked perfectly. I am using Version 2.2.0-alpha03 of navigation component. After added those params to the action action_inboxFragment_to_conversation_graph, now the InboxFragmentDirections.ActionInboxFragmentToConversationGraph is generated correctly.

<?xml version="1.0" encoding="utf-8"?>
<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/messages_graph"
    app:startDestination="@id/inboxFragment">
    <fragment
        android:id="@+id/inboxFragment"
        android:name="com.wlpr.docfinder.ui.fragment.InboxFragment"
        android:label="fragment_inbox"
        tools:layout="@layout/fragment_inbox" >
        <action
            android:id="@+id/action_inboxFragment_to_conversation_graph"
            app:destination="@id/conversation_graph">
            <argument
                android:name="participantName"
                android:defaultValue="Conversation"
                app:argType="string"
                app:nullable="true" />
            <argument
                android:name="documentsCount"
                android:defaultValue="1"
                app:argType="integer" />
        </action>
    </fragment>
    <navigation
        android:id="@+id/conversation_graph"
        android:label="conversationGraph"
        app:startDestination="@id/conversationFragment">
        <fragment
            android:id="@+id/conversationFragment"
            android:name="com.wlpr.docfinder.ui.fragment.ConversationFragment"
            android:label="fragment_conversation"
            tools:layout="@layout/fragment_conversation">
            <action
                android:id="@+id/action_conversationFragment_to_reportingDetailsFragment"
                app:destination="@id/reportingDetailsFragment" />
            <argument
                android:name="participantName"
                android:defaultValue="Conversation"
                app:argType="string"
                app:nullable="true" />
            <argument
                android:name="documentsCount"
                android:defaultValue="1"
                app:argType="integer" />
        </fragment>
        <!-------- more fragments... -------->
</navigation>

1 Comment

What are you overriding here?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.