Type-Safe Navigation in Jetpack Compose

Vivek Yadav
3 min readNov 19, 2024

--

Navigating between screens is a fundamental aspect of any mobile application. With the introduction of Jetpack Compose, Android developers have a new way to create UIs declaratively. However, managing navigation can still be a challenge. In this blog post, we will explore how to implement type-safe navigation in Jetpack Compose using the Jetpack Navigation library.

Getting Started

To use Jetpack Navigation in your Jetpack Compose project, you need to add the following dependency to your build.gradle file:

dependencies {
val nav_version = "2.8.4"
implementation("androidx.navigation:navigation-compose:$nav_version")

/*serialization*/
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")
}

This dependency allows you to use the navigation components specifically designed for Jetpack Compose.

Note: Type Safe Navigation Required Without Serialization Type-Safe Navigation Won’t Work.

Setting Up Navigation

Let’s create a simple application with two screens: a Home screen and a Detail screen. We will navigate from the Home screen to the Detail screen when the user clicks a button.

Step 1: Create the Screens

First, we need to create the composable functions for our two screens.

@Composable
fun HomeScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Home Screen", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { navController.navigate("detail") }) {
Text(text = "Go to Detail Screen")
}
}
}

@Composable
fun DetailScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Detail Screen", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { navController.popBackStack() }) {
Text(text = "Back to Home Screen")
}
}
}

Step 2: Set Up the Navigation Graph

Next, we need to set up the navigation graph, which defines the navigation paths between the screens.

@Composable
fun NavigationGraph(navController: NavController) {
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("detail") { DetailScreen(navController) }
}
}

Step 3: Create the Main Activity

Now, let’s set up our MainActivity to host the navigation graph.

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavigationGraph(navController)
}
}
}

Complete Code Example

Here’s the complete code for the application:

package com.example.navigationdemo

import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.*
import androidx.compose.material3.Button
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable
import androidx.navigation.compose.rememberNavController

class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
val navController = rememberNavController()
NavigationGraph(navController)
}
}
}

@Composable
fun NavigationGraph(navController: NavController) {
NavHost(navController, startDestination = "home") {
composable("home") { HomeScreen(navController) }
composable("detail") { DetailScreen(navController) }
}
}

@Composable
fun HomeScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Home Screen", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { navController.navigate("detail") }) {
Text(text = "Go to Detail Screen")
}
}
}

@Composable
fun DetailScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxSize()
.padding(16.dp),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
Text(text = "Detail Screen", fontSize = 24.sp)
Spacer(modifier = Modifier.height(16.dp))
Button(onClick = { navController.popBackStack() }) {
Text(text = "Back to Home Screen")
}
}
}

Benefits of Using Jetpack Navigation with Compose

  1. Type-Safe Navigation: The navigation library provides a type-safe way to navigate between screens, reducing the chances of runtime errors.
  2. Declarative UI: Jetpack Compose allows you to build your UI in a declarative manner, making it easier to understand and maintain.
  3. Lifecycle Awareness: The navigation component is lifecycle-aware, meaning it automatically handles navigation based on the lifecycle of your composables.
  4. Easy Back Navigation: The popBackStack() method makes it simple to navigate back to the previous screen.

Note: For Info You Can Read From Official Documentation

Conclusion

In this blog post, we explored how to implement type-safe navigation in a Jetpack Compose application using the Jetpack Navigation library. With just a few lines of code, we were able to set up a simple navigation flow between two screens.

#Android #JetpackCompose #Kotlin #Navigation #KMM

--

--