Navigating in a pure jetpack compose project — part #1
How to use navigation component in the compose world where there are no fragments
Check out all the articles in the series:
• Navigating in a pure jetpack compose project — part #1
• Navigating in a pure jetpack compose project — part #2
Jetpack compose is the new kid on the block. Though its relatively new, compared to the traditional android UI toolkit, soon will come those days when projects will start migrating to jetpack compose, and more & more companies will put it as a requirement for their potential android developer. As of the publishing date of this article, the argument “will composables completely replace fragments or views?” has not been achieved yet. There are certain things, on the other hand, which have been achieved with jetpack compose, one of which is navigation among different composables. Let’s take a look and see how jetpack’s navigation component library works seamlessly with jetpack compose.
Adding the dependencies
First thing that you will need is to bring in the following jetpack navigation component dependency designed specifically by keeping jetpack compose in mind:
Now that we have our dependencies in order, let’s start with discussing how navigation actually happens among composables.
NavController — The good Ol’ friend
If you have used navigation component in the past, then you are going to feel right at home (well almost). Similar to legacy UI toolkit, we are going to use NavController
here as well, as it will act as our central API. Navigation component will also manage our backstack
and add or remove the composables
from it.
Simply add the navController
to your composable as shown below:
As recommended in the navigation for compose docs, it’s a good idea to place this navController
at a hierarchical level where other composables can easily access it. This way you can update the composables that are outside your screen (i.e. manage the ones present in the backStack
)with the help of navController
and the state it provides via currentBackStackEntryAsState()
.
However, if you go on a refresher course on navigation component, you would soon realize that every navController
need its partner-in-crime, the NavHost
. The NavHost
is responsible for linking the NavController
with a navigation graph that specifies all the composable destinations that you should be able to navigate between. As you navigate to different composables, the content of the navHost
gets switched with the destination you reached at, or to say that your navHost
gets recomposed
. In the case of legacy UI toolkit, this NavHost
was a FragmentContainerView
. Each composable in your navigation graph acts as a destination and is reachable via a route
.
A
Route
is aString
that defines a path to your composable. Think of it as an implicit deep-link that leads to a specific destination in your application. Each destination in your navigation graph, or each composable, must have a uniqueroute
to avoid collision.
To create the NavHost
, you will need the navController
that we previously ‘remembered’ in our composable, and the name of the startDestination
composable. With the help of a little Kotlin DSL magic, here is how to create a NavHost
:
Now that all the elements of navigation component are setup, comes the time to actually navigate to another composable. In order to carry out this transaction, simply use navigate()
method on the navController
instance as follow:
Keep in mind composables
recompose
multiple times. So make sure to use thenavigate()
method in acallback
and not in the composable itself.
NavController
also provides you with the APIs to manage the backstack
with composables as well, similar to how it does for the the native UI toolkit. For instance, in order to pop the backstack
everything up to the mentioned destination, you can do the following:
Similarly, you can also include the inclusive
flag, which will also pop the mentioned destination from backstack
as well, in our case the home
composable:
Much like how activities or fragments provide us with managing their various instances in the backstack
with the help of launch modes
, similarly composables can make use of those launch modes
as shown below:
Passing arguments between destinations
In order to pass arguments between our composables, we would need to modify the routes
we defined in our NavHost
. This is eerily similar to how we define PATHS
in a retrofit service, as shown below:
Now in order to pass arguments, simply switch the userId
parameter in the navigate()
method call and pass in the actual value as show below:
Adding Deep Links to composables
Jetpack compose UI would not have a good interoperability with the existing UI toolkit unless it solves the problem of providing deeplinks
to the composables. Follow the steps below in order to add an implicit deep link to your composable destination:
One last step to complete the deeplinks
setup would be to add the <intent-filter>
to our manifest.xml
file. Add the following to your activity to allow 3rd party apps to open your application:
In part #2, we will see how to implement BottomNavigation
in jetpack compose and how to use navigation component with it to navigate to different composables.