32

In my first graph, I have the following:

<?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/firstGraph"
    app:startDestination="@id/listFragment">

    <fragment
        android:id="@+id/listFragment"
        android:name="com.example.ListFragment">

        <action
            android:id="@+id/action_list_to_details"
            app:destination="@id/detailsFragment" />

    </fragment>

    <fragment
        android:id="@+id/detailsFragment"
        android:name="com.example.DetailsFragment">

    </fragment>
</navigation>

In my second graph I have the following:

<?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/secondGraph"
    app:startDestination="@id/dashboardFragment">

    <include app:graph="@navigation/firstGraph" />

    <fragment
        android:id="@+id/dashboardFragment"
        android:name="com.example.DashboardFragment">
        <action
            android:id="@+id/action_dashboard_to_notification"
            app:destination="@id/notificationFragment"/>
    </fragment>

    <fragment
        android:id="@+id/notificationFragment"
        android:name="com.example.NotificationsFragment">

        <action
            android:id="@+id/action_notification_to_details"
            app:destination="@id/firstGraph"/>

    </fragment>
</navigation>

I want to navigate from "notificationFragment" to "detailsFragment" directly without it being the start destination, with including the second graph stack

Ahmad Abdullah
  • 1,645
  • 1
  • 16
  • 25
  • 1
    I have this same problem. I thought about removing the nested graphs (at the cost of a mess), but even that I can't do because I'm using view models shared by a graph context. – FirstOne Feb 15 '20 at 22:34
  • 1
    I had previously managed to make it work by creating a "temp" dest as start of a graph which receives a parameter that it reads and uses to re-navigate - popping itself. This works, but then it breaks shared element transition animations. – FirstOne Feb 15 '20 at 22:36
  • I temporarily solved it by duplicating the graphs, I probably shared your opinion to decide not to use it, but it's looked pretty navigation method just like storyboards in iOS – Ahmad Abdullah Feb 16 '20 at 11:25

1 Answers1

48

As per the nested graph documentation:

[Nested graphs] also provide a level of encapsulation — destinations outside of the nested graph do not have direct access to any of the destinations within the nested graph.

There is one exception to that, when you are navigating using a URI, effectively deep linking into any destination:

Unlike navigation using action or destination IDs, you can navigate to any URI in your graph, regardless of whether the destination is visible. You can navigate to a destination on the current graph or a destination on a completely different graph.

Therefore you can add an implicit deep link to your graph:

<fragment
    android:id="@+id/detailsFragment"
    android:name="com.example.DetailsFragment">
    <deepLink app:uri="android-app://your.package.name/details" />
</fragment>

Then navigate to that destination via URI:

val uri = Uri.parse("android-app://your.package.name/details")
navController.navigate(uri)

It doesn't matter what your URI is, as long as the <deepLink> and what you pass to navigate match. Any arguments you have would need to be encoded in the URL.

FirstOne
  • 6,033
  • 7
  • 26
  • 45
ianhanniballake
  • 191,609
  • 30
  • 470
  • 443
  • 3
    This seems promising, but I'd say it would get weird when the argument is an object - because then I'd have to break the object properties and pass one by one in the URL. – FirstOne Feb 16 '20 at 11:48
  • 1
    Also, the deeplink creates the backstack: _"When nesting graphs, the start destination from each level of nesting—that is, the start destination from each element in the hierarchy—is also added to the stack."_. So, this could cause some weird behavior where the user sees a screen for which they haven't been to. – FirstOne Feb 16 '20 at 11:51
  • Wonderfull answer!! Thank you, But I think it's not complete. As @FirstOne said: It's missed the destination fragment stack problem, one more thing; what if I would pass a serialized (or Parcelable) object as a parameter. it seems it needs a workaround to pass the parameters – Ahmad Abdullah Feb 16 '20 at 12:31
  • 1
    @FirstOne - navigating by URI does not add any synthetic back stack destinations. That's what the line `When navigating using URI, the back stack is not reset. This is unlike other deep link navigation, where the back stack is replaced when navigating.` means in that documentation. – ianhanniballake Feb 16 '20 at 16:44
  • 1
    @AhmadAlselwadi - yes, that's exactly what I meant when I specifically said `Any arguments you have would need to be encoded in the URL.` – ianhanniballake Feb 16 '20 at 16:45
  • @ianhanniballake Thank you very much for your answer and clarifications, I tried a few workarounds like replacing graphs at run time but unfortunately, I lost the previous graph navigation, also I tried to add the details fragment to the first graph as a new destination and also could get the second graph navigation – Ahmad Abdullah Feb 16 '20 at 17:34
  • 1
    @AhmadAlselwadi - yes, navigating by URI is the only mechanism that works. – ianhanniballake Feb 16 '20 at 17:54
  • @ianhanniballake Ok.. I'll see if I can test it later. The only problem then is passing arguments to the destination. Adding them to the URL seems like it could become a mess. – FirstOne Feb 16 '20 at 18:01
  • 1
    @FirstOne - think about if you were building a website. Would you encode your information in the URL directly or would you have a common repository for the information and only pass an identifier in your URL? Same problem here (and the same recommendation: just pass an identifier) – ianhanniballake Feb 16 '20 at 18:05
  • Too bad there is no other way. Some screens were just "plug and play" with required input and some output. Well, I guess I have a lot of work to do.. @ianhanniballake – FirstOne Feb 16 '20 at 18:23
  • 3
    @FirstOne - given that arguments count against the limited amount of data you can put in saved instance state (or face a `TransactionTooLargeException`, particularly since newer versions of Android lower that limit even more so), passing an identifier is a better way of doing things in all cases, not just this particular one. – ianhanniballake Feb 16 '20 at 19:24
  • Thank you again @ianhanniballake, it's a wonderful answer, but seems no way to have all of the second graph stack (the only solution worked for me is create another duplicated stack included the needed destinations) – Ahmad Abdullah May 08 '20 at 22:56
  • @ianhanniballake what is the downside of just using global action for this, besides breaking of the encapsulation? – Torima Jun 16 '22 at 11:23
  • @ianhanniballake Can you please provide a similar solution for Jetpack Compose also in case of Bottom Tab ? How to navigate to nested composable in other graph and pressing back it should retain previous tab state ? – Parveen Sharma Jun 29 '22 at 04:29