I have an app that manages Boxes
.
This app has a single activity and uses fragments as destinations.
It has (among others) the following destinations/fragments:
Home
(registered as topLevelDestination)BoxesManagement
(registered as topLevelDestination)BoxEdit
From the home destination I want to offer a convenient link to create a new box.
For that I want to link BoxEdit
directly, but with BoxesManagement
in the back stack.
Attempt 1 - Explicit Deep Linking
Since an intermediate destination will only land on the back stack when it is the start destination of a <navigation>
element, I placed BoxesManagement
(as start) and BoxEdit
in a nested graph.
The nested graph is in a separate file, but <include>
d in the parent graph.
Then I used:
findNavController()
.createDeepLink()
.setDestination(R.id.nav_edit_box)
.createPendingIntent()
.send()
This did work in the way that it got me to the desired destination with BoxesManagement
in the back stack.
However, it causes two issues:
- The application is started again. At least that is what I assume happens, since the entire screen flashes very briefly. This behavior lets me assume that I am not supposed to be using deep links for in-app navigation. (This is not surprising as the documentation never hints at this use-case.)
- When I go back to
BoxesManagement
, I see the hamburger menu icon (as expected). But when I use the drawer menu to navigate toHome
, nothing happens.
Attempt 2 - Direct Navigation
findNavController()
.navigate(R.id.nav_box_edit)
This does not work and simply fails with:
java.lang.IllegalArgumentException: Navigation action/destination <APP-PKG>:id/nav_box_edit cannot be found from the current destination Destination(<APP-PKG>:id/nav_home) label=Home class=<APP-PKG>.ui.HomeFragment
I am not surprised, as Murat Yener from Google already pointed out that this is not supported.
Attempt 2b - Setting the Graph
From this question and answer I got the idea to set the graph on the nav controller before navigating.
findNavController().apply {
setGraph(R.navigation.nav_graph_boxes)
navigate(R.id.nav_box_edit)
}
This does work, but also causes two issues:
- When following this navigation, the nav-controller's graph is now
R.navigation.nav_graph_boxes
instead ofR.navigation.nav_graph
. When I use a different path with single steps throughBoxesManagement
, I can also reachBoxEdit
but withR.navigation.nav_graph
as the controller's graph. - The same issue as above with deep linking, navigating to
Home
using the drawer menu does nothing. I believe this is actually a direct consequence of the first issue.
The proposed solution in the linked Q&A is to set the graph back to R.navigation.nav_graph
when navigating back.
I don't know where in the code to do that though, as I don't navigate back through any explicit action, but rather through the up-button and the drawer menu, which - as stated before - does not work anymore with this approach.
Attempt 3 - Implicit Deep Linking
As suggested by the official doc I decided to try implicit deep linking, even though that brings none of that sweet type-safety that I was promised when using the navigation component.
I added
<deepLink app:uri="android-app://my.app.url/boxes/{boxId}/edit"/>
to the nav_box_edit
fragment definition and used
findNavController()
.navigate(Uri.parse("android-app://my.app.url/boxes/0/edit"))
from the Home
destination.
This got me to my destination, but again I have a problem with this:
- It does not put
BoxesManagement
into the back stack (this is to be expected per the documentation).
Question
How do I properly navigate to a (nested) destination while putting another destination on the back stack before it?
navigate()
twice? – Denazifynavigate()
meant: "Go here, now! Don't do anything else" I wrongly assumed that execution would just continue with the lifecycle of the target destination. – Limnetic