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.
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:
BoxesManagement
, I see the hamburger menu icon (as expected). But when I use the drawer menu to navigate to Home
, nothing happens.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.
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:
R.navigation.nav_graph_boxes
instead of R.navigation.nav_graph
. When I use a different path with single steps through BoxesManagement
, I can also reach BoxEdit
but with R.navigation.nav_graph
as the controller's graph.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.
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:
BoxesManagement
into the back stack (this is to be expected per the documentation).How do I properly navigate to a (nested) destination while putting another destination on the back stack before it?
In order to create a back stack as desired, you just have to push all desired destinations on the stack:
findNavController().apply {
navigate(R.id.nav_boxes_management)
navigate(R.id.nav_box_edit)
}
This works only if all destinations are in the same nav graph. As specified in the question, this is not the case here, so a slightly different approach needs to be taken:
findNavController().apply {
navigate(FragmentHomeDirections.actionBoxesManagement())
navigate(FragmentBoxesManagementDirections.actionEditBox(0L))
}
Using the directions of the now-top-of-the-stack destination BoxesManagement
, the navigation into the nested graph succeeds.
(Thanks to ianhanniballake for giving me the crucial hint!)
Home
This works, but I don't know why:
findNavController().apply {
navigate(FragmentHomeDirections.actionBoxesManagement(), navOptions {
popUpTo(R.id.nav_home) {
inclusive = false
saveState = true
}
})
navigate(FragmentBoxesManagementDirections.actionEditBox(0L))
}
I figured it out by looking at the source code of NavigationUI
, which effectively handles the drawer menu actions.