Jetpack Compose Navigation(Single Module and MultiModule)

I guess each of one is aware of Jetpack compose (at least heard the name of it). Jetpack compose navigation was a scary topic for me when I started learning compose . Then found a simple to tackle this . Let’s go through the process together.
We are going to build the following screens ; From Screen 1
, we go to Screen 2
and pass a string as an argument.

Dependencies
implementation "androidx.navigation:navigation-compose:2.6.0-alpha04"
We are using the normal compose navigation library. You can also use Compose destinations to do navigation using compose.
Setting up routes for the screens
sealed class NavigationItem(val route: String) {
object Screen1 : NavigationItem(
route = "screen_1"
)
object Screen2 : NavigationItem(
route = "screen_2"
)
}
This NavigationItem
class serves as the place to mention all the routes for different screens.
Create the Navigation Graph
@Composable
fun NavigationGraph(
navController: NavHostController,
startLocation: String
) {
NavHost(
navController = navController,
startDestination = startLocation
) {
composable(
route = NavigationItem.Screen1.route
) {
Screen1(
navigateTo = {
navController.navigate(it)
}
)
}
composable(
route = NavigationItem.Screen2.route + "?name={name}",
arguments = listOf(
navArgument("name"
) {
type = NavType.StringType
defaultValue = "Test"
nullable = true
}
)
) {
Screen2(navigateTo = { navController.navigate(it) }, name = it.arguments?.getString("name"))
}
}
}
Now we create the NavigationGraph
class. We need a NavHostController
to do the navigation in compose. We also pass a startDestination
parameter, which determines which screen will be shown in the beginning. Inside the NavHost
we mention the routes for a screen and it’s corresponding compose screen. For screen1
, we are calling the Screen1
compose function(the screen); we are also passing a lambda, so that that lambda can be used to do navigation in different screens.
In case of Screen2
, we are passing an optional parameter name
; and we also mention the parameter type; it’s defaultValue
and whether the param is nullable or not . While calling the Screen2
composable , we directly pass the name param from the argument to the Screen2
composable from here only.
Screen 1 Compose
@Composable
fun Screen1(navigateTo: (String) -> Unit) {
var text by remember {
mutableStateOf("")
}
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Screen 1")
Spacer(modifier = Modifier.height(20.dp))
TextField(value = text, onValueChange = {
text = it
})
Spacer(modifier = Modifier.height(20.dp))
Button(
onClick = {
// Navigating with name variable
navigateTo(NavigationItem.Screen2.route + "?name=$text")
// Navigating without the name variable , in this case the name
// variable will take the default value mentioned the NavigationGraph
// navigateTo(NavigationItem.Screen2.route)
},
modifier = Modifier.fillMaxWidth()
) {
Text(text = "Click to go to Screen 2")
}
}
}
Screen 2 Compose
@Composable
fun Screen2(navigateTo: (String) -> Unit, name: String?) {
Column(
modifier = Modifier.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(text = "Screen 2")
Spacer(modifier = Modifier.height(20.dp))
Text(text = "Name passed from previous screen:\n $name")
}
}
Calling from MainActivity
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ComposeNavigationExampleTheme {
//We create this navcontroller so that it will help us in navigating through different screens
val navController = rememberNavController()
Column(modifier = Modifier.fillMaxSize()) {
NavigationGraph(navController = navController, startLocation = NavigationItem.Screen1.route)
}
}
}
}
}
We are creating the navController
and calling the NavigationGraph
from MainActivity
. As we have passed the startLocation
as Screen1
, the Screen1
will be shown first.
Bazinga!!! You can now develop navigation in Single module Jetpack compose apps.
Multi-Modular apps
Let’s talk about navigation in Fully Compose Multi Module Android app.
Let’s first understand the app structure first.
app
— Contains the MainActivity and responsible for running the appbuildSrc
— Contains centralized dependenciescommon
— Common functions like Network, interceptors etc.contact_picker
— Used to pick multiple contacts from devicedesign
— Design library used for the appfeature_home
,feature_profile
,feature_space
,feature_transaction
,authentication
— These modules are the feature modules for the app.
All the feature modules use design
and common
modules to work easily and effectively.
We are following the same way which we used to navigate in single module app. I am not mentioning the code here ;
NavigationItems
— It is placed inside thecommon
module containing all the paths for the screens- In the app module, define the
NavigationGraph
so that we can navigate to all the screens. - In the
MainActivity
which is placed insideapp
, we can call theNavigationGraph
.
You can get the code from this repo.