Status Update
Comments
il...@google.com <il...@google.com> #2
As a workaround, your sub_nav_graph.xml
should remove this line:
<include app:graph="@navigation/sub_nav_graph_2" />
sub_nav_graph_2
is already added at the top most level, so adding it again means a second copy of that same graph in your overall graph, triggering this error message.
It isn't a circular reference, but it is an error on your part - you should only have a graph added at most one time to your graph.
al...@gmail.com <al...@gmail.com> #3
Thanks for your fast response!
Problem we are facing is a bit more complex.
We experienced some problems when trying to navigate between nav graphs using safe args because support classes doesn't map arguments as we wanted. So I.E. an action from sub_nav_graph
to sub_nav_graph_2
:
<include app:graph="@navigation/sub_nav_graph_2" />
<fragment
android:id="@+id/mainFragment"
android:name="com.example.myapplication.MainFragment"
android:label="MainFragment" >
<action
android:id="@+id/action_to_sub_nav_graph_2"
destination="@id/sub_nav_graph_2" >
</fragment>
Will give us in return fun MainFragmentDirections.actionToSubNavGraph2()
without any argument from sub_graph_2
's start destination (if any).
To amend this we started using global actions as entry points to our sub graphs. I.E in sub_nav_graph_2
<navigation
android:id="@+id/sub_nav_graph_2"
app:startDestination="@id/mainFragment">
<action
android:id="@+id/action_to_sub_nav_graph_2"
destination="@id/sub_nav_graph_2" >
<argument
android:name="arg1"
app:argType="string" />
</action>
<!-- fragments here -->
By doing this, we now have a fun SubNavGraph2Directions.actionToSubNavGraph2(arg1: String)
available for us.
With this in place when we want to navigate to sub_graph_2
from a different graph, we use this function instead.
But when we remove the import from sub_nav_graph
action id is not recognised any more and app crashes at runtime when trying to navigate.
We can update the example if this is not clear enough.
sp...@google.com <sp...@google.com> #4
Sending back to Ian for
(I have a pending CL to update the error message)
il...@google.com <il...@google.com> #5
Re #3 - you've made a lot of bad assumptions, so let's start from the beginning.
As per the action_to_sub_nav_graph_2
within sub_nav_graph_2
is therefore almost completely useless - nothing outside of the graph can reference that action to navigate to the graph or use SubNavGraph2Directions.actionToSubNavGraph2(arg1: String)
and treating it as if it is visible is always going to fail (that's why it is in the SubNavGraph2Directions
class - you need to be in sub_nav_graph_2
to use it).
The same basic tenant of visibility applies the other direction as well: actions or destinations in a graph are also available to every other destination in that graph or any of the destinations in a nested or included graph. This is exactly why you don't need a second copy of <include app:graph="@navigation/sub_nav_graph_2" />
in your final graph - as long as it is added at any layer above who is using it, the graph itself is already visible. Adding a second visible copy doesn't help anything and actively confuses the cases where that graph has a deep link (which copy should you deep link to if there are multiple copies?).
You seem to be trying to work around two existing issues in Safe Args that are entirely orthogonal to this issue with manifest merger:
- Safe args plugin doesn't work across separate filesb/133170983 - Navigation subgraphs do not use the arguments of their startDestinationb/109505019
Due to the first issue, if you want to use Safe Args to reference a destination from outside of that individual file (say, the <include>
in your main_nav_graph
), you need to declare an <action>
in that file (importantly, not an <include>
), copying the arguments from the start destination of the graph (to work around the second issue):
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/home_nav_graph"
app:startDestination="@id/mainFragment">
<action
android:id="@+id/action_to_sub_nav_graph_2"
destination="@id/sub_nav_graph_2" >
<argument
android:name="arg1"
app:argType="string" />
</action>
<fragment
android:id="@+id/mainFragment"
android:name="com.example.myapplication.MainFragment"
android:label="MainFragment" />
</navigation>
Note that this action references sub_nav_graph_2
, which is already available because your main_nav_graph
has an <include>
for it. That's what actually makes it transitively visible to your sub_nav_graph
without you needing to add another <include>
. It is totally fine to have multiple actions at multiple levels of your hierarchy all pointing to the same destination.
I'd suggest filing separate bugs for issues you encounter with Safe Args and with crash issues - it is always best to treat each issue independently.
Given all that, we still need to improve the error message here, since this isn't a circular reference between graphs.
al...@gmail.com <al...@gmail.com> #6
Hey, thanks for you answer again.
Now we understand why we were experiencing this error (related to duplicate imports). Thanks for the explanations on this topic.
However, now i'm a bit worried about your comments about actions are only valid with that graph.
As long as we use the same android:id
for an action in different graphs, we are able to use any of the support classes to create that action and use it to navigate from any fragment holding it.
Is this a bad practice or something i should report as well in a different issue?
i updated the sample in a different branch to show it in action (
il...@google.com <il...@google.com> #7
The only generated class you should be using in a particular destination is for the one associated with the destination you're on - i.e., your HomeFragment
would use HomeFragmentDirections
. Each Directions
class has the proper superclass set that allows you to access global actions at the graph level (which is why the approach in
Due to the issues I listed, that superclass approach does not work across files (i.e., Directions
classes in your <include>
graphs do not see actions defined in main_nav_graph
). That's why Directions
classes.
You could certainly define that global action at the main_nav_graph
level and use MainNavGraphDirections
since you know that, if there weren't the issues I listed, that would be the superclass of your HomeNavGraphDirections
and would be in scope, but that makes a big assumption that the only place your graph is <include>
d in is your main_nav_graph
(which probably is the case for you).
sp...@google.com <sp...@google.com> #8
Fixed in AGP 4.2.0-alpha04.
A navigation file included multiple times in a navigation graph will result in a warning instead of an error now.
Circular references will still result in an error.
ha...@gmail.com <ha...@gmail.com> #9
il...@google.com <il...@google.com> #10
Re #9 - this about graph A including graph B. Graph B should not also include graph A (as then graph A would inflate...which would inflate another nested copy of graph B...which would inflate another nested copy of graph A). Graph A, and all of its destinations already exist and can be navigated to by graph B (as destinations in parent graphs are always accessible); it never needs to be included again as a nested copy.
Description
Component used: Navigation Component Version used: 2.3.0-beta01 Devices/Android versions reproduced on: it is a compile erro
After adding the different subgraphs and the
<nav-graph android:value="@navigation/main_nav_graph" />
line to the manifest to handle deeplinks you can already get the error at compile time:Thank you!