Jetpack Compose Navigation(Single Module and MultiModule)

Sourav Saikia
4 min readDec 25, 2022

Image from Android Developers

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.

Multi-Module app modules
  • app — Contains the MainActivity and responsible for running the app
  • buildSrc — Contains centralized dependencies
  • common — Common functions like Network, interceptors etc.
  • contact_picker — Used to pick multiple contacts from device
  • design — Design library used for the app
  • feature_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 the common 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 inside app , we can call the NavigationGraph .

You can get the code from this repo.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response