CPS251 Android Development by Scott Shaper

Introduction to Navigation

What is Navigation?

Think of navigation in Android apps like moving between different rooms in a house. Just as you need doors and hallways to move from one room to another, your app needs a way to move between different screens. In Android Compose, we use the Navigation component to create these "doors" between screens, making it easy for users to move around your app.

Whether you're building a social media app where users need to move between their feed and profile, or a shopping app where users browse products and view their cart, navigation is essential for creating a smooth user experience.

Why Do We Need Navigation?

  • Move between different screens in your app
  • Create a back button experience
  • Pass data between screens
  • Handle user flow and app structure
  • Manage screen history

Quick Reference: Navigation Components

Component What It Does When to Use It
NavHost Container for navigation destinations Setting up the navigation structure
NavController Manages navigation between screens Handling navigation actions
composable() Defines a navigation destination Adding new screens to navigate to
navController.navigate() Performs navigation Moving between screens

Setting Up Navigation Dependencies

Before you can use navigation in your app, you need to add the required dependencies. These dependencies provide the navigation components and functionality we'll be using.

Add to libs.versions.toml

[versions]
    # ... other versions ...
    navigation-compose = "2.7.7"
    
    [libraries]
    # ... other libraries ...
    androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigation-compose" }
    

Add to app/build.gradle.kts

dependencies {
        // ... other dependencies ...
        implementation(libs.androidx.navigation.compose)
    }
    

After adding these dependencies, sync your project with Gradle files. You'll then be able to use all the navigation components we'll discuss in these lessons.

Basic Navigation Example

@Composable
    fun SimpleNavigationExample() {
        val navController = rememberNavController()
    
        NavHost(
            navController = navController,
            startDestination = "home"
        ) {
            composable("home") {
                HomeScreen(
                    onNavigateToProfile = {
                        navController.navigate("profile") {
                            launchSingleTop = true
                        }
                    }
                )
            }
            composable("profile") {
                ProfileScreen(
                    onNavigateBack = {
                        navController.popBackStack()
                    }
                )
            }
        }
    }
    
    @Composable
    fun HomeScreen(onNavigateToProfile: () -> Unit) {
        Box(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier
                    .padding(top = 50.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Button(onClick = onNavigateToProfile) {
                    Text("Go to Profile")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Text(
                    "This is the home page",
                    modifier = Modifier.padding(16.dp)
                )
            }
        }
    }
    
    @Composable
    fun ProfileScreen(onNavigateBack: () -> Unit) {
        Box(modifier = Modifier.fillMaxSize()) {
            Column(
                modifier = Modifier
                    .padding(top = 50.dp),
                horizontalAlignment = Alignment.CenterHorizontally
            ) {
                Button(onClick = onNavigateBack) {
                    Text("Back to Home")
                }
                Spacer(modifier = Modifier.height(16.dp))
                Text(
                    "This is the profile page",
                    modifier = Modifier.padding(16.dp)
                )
            }
        }
    }

What's Happening in the above example?

Let's break down this Kotlin code we have just two screens: a "Home" screen and a "Profile" screen. In our app, these screens are different screens users can visit.

The "Navigation Manager" - rememberNavController()

  • val navController = rememberNavController(): The navController knows all the screens, how to get to them, and keeps track of which screens you've visited.

The "Blueprint" - NavHost

  • NavHost(...) { ... }: This is like a blueprint of our app. It defines all the possible screens and the paths between them.
  • startDestination = "home": This tells our app (navController) to always start on the "home" screen when the app begins.

Defining Our "Screens" - composable()

  • composable("home") { ... }: This line defines our "Home" screen. When the app is told to go to "home", it shows whatever is inside this curly brace block – in this case, our HomeScreen.
  • composable("profile") { ... }: Similarly, this defines our "Profile" screen, which will show the ProfileScreen when visited.

Moving to Another Screen - navController.navigate()

  • navController.navigate("profile") { launchSingleTop = true }: When you click the "Go to Profile" button on the Home screen, this is like telling your app, "Take me to the Profile screen!"
    • The launchSingleTop = true part is a special instruction. If you are already on the "Profile" screen, then it won't open a brand new, identical "Profile" screen on top of the stack. It will just make sure we're seeing the existing one. This helps prevent bugs and keeps your app smooth.

Going Back - navController.popBackStack()

  • navController.popBackStack(): When you click the "Back to Home" button on the Profile screen, this is like telling your app, "Okay, I'm done with this screen, take me back to the one I just came from!" The app then removes the current screen (Profile) from its history and shows the previous one (Home).

In Simple Terms:

  1. The app starts, and our navigation manager (rememberNavController) sets up the app (NavHost), starting us in the "home" screen (HomeScreen).
  2. On the Home screen, we see a button that says "Go to Profile".
  3. When we click it, the navigation manager takes us to the "profile" screen (ProfileScreen). Because of `launchSingleTop = true`, it ensures we don't accidentally create multiple copies of the profile screen on the stack.
  4. On the Profile screen, we see a button that says "Back to Home".
  5. When we click it, the navigation manager sends us back to the "home" screen, just like hitting a back button.

How this example renders

Above is just a snippet of the code to view the full code, you need to go to my GitHub page and look at the chapter9 intro.kt file.

The first image shows the home screen. The second image shows the profile screen.

Basic Navigation Example Basic Navigation Example

Tips for Getting Started

  • Plan your navigation structure before implementing
  • Use meaningful names for your routes
  • Start with simple navigation before adding complexity
  • Test navigation on different screen sizes

Common Mistakes to Avoid

  • Creating circular navigation paths
  • Forgetting to handle the back button
  • Using hardcoded route names
  • Not planning navigation structure