Skip to main content
Android Development with Kotlin
CHAPTER 14 Beginner

Navigation Between Activities and Fragments

Updated: May 16, 2026
20 min read

# CHAPTER 14

1. Introduction

A mobile application is rarely a single, static screen. Users expect to tap a login button and be transported to a dashboard, or tap a product image and seamlessly transition to a detailed checkout page. In the Android ecosystem, moving the user through the application is called Navigation. In this chapter, we will master the historical and modern architectures of Android Navigation. We will learn how to launch new screens utilizing Intents, pass data safely between Activities using Intent Extras, manage the Back Stack, and introduce the modern Jetpack Navigation Component.

2. Learning Objectives

By the end of this chapter, you will be able to:
  • Differentiate between Explicit Intents and Implicit Intents.
  • Launch a new Activity using startActivity().
  • Transmit string and integer data between screens using putExtra().
  • Understand how Android manages screen history via the "Back Stack".
  • Conceptualize the visual workflow of the Jetpack Navigation Component.

3. The Concept of "Intents"

In Android, you cannot simply write DetailActivity.open(). The OS isolates every screen for security. To move from Screen A to Screen B, you must send an official request to the Android Operating System. This request is called an Intent (you are declaring your *intent* to do something).

There are two types of Intents:

  1. 1. Explicit Intent: You tell the OS exactly which screen inside your app to open (e.g., "Open SettingsActivity").
  1. 2. Implicit Intent: You ask the OS to perform a general action (e.g., "Open a web browser", "Take a photo"), and the OS decides which external app should handle it.

4. Basic Navigation (Explicit Intents)

Let's assume we have two screens: MainActivity.kt and DetailsActivity.kt. *(Note: Whenever you create a new Activity, it MUST be registered in the AndroidManifest.xml! Android Studio does this automatically if you right-click the folder and select New -> Activity).*

Here is how we launch the DetailsActivity when a button is clicked:

kotlin
1234567891011
// Inside MainActivity.kt
val navigateButton = findViewById<Button>(R.id.navBtn)

navigateButton.setOnClickListener {
    // 1. Create the Intent. 
    // Context = 'this' (Where we are), Target = 'DetailsActivity::class.java' (Where we are going)
    val intent = Intent(this, DetailsActivity::class.java)
    
    // 2. Tell the OS to execute the transition!
    startActivity(intent)
}

5. Passing Data Between Screens (Intent Extras)

If a user taps on "Product #45", the Details screen needs to know the ID is 45 so it can load the correct image. We pass this data using Intent Extras. Think of an Intent as an envelope. You can stuff variables inside the envelope before you mail it to the next screen!

Sending the Data (Screen A):

kotlin
123456
val intent = Intent(this, DetailsActivity::class.java)
// Stuffing data into the envelope using Key-Value pairs!
intent.putExtra("USERNAME", "Alex")
intent.putExtra("USER_AGE", 25)

startActivity(intent)

Receiving the Data (Screen B / DetailsActivity):

kotlin
12345678910111213
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_details)

    // Opening the envelope!
    // We look for the Key "USERNAME". If we can't find it, we return a default value.
    val incomingName = intent.getStringExtra("USERNAME") ?: "Unknown User"
    
    // For Ints, the fallback default value is mandatory!
    val incomingAge = intent.getIntExtra("USER_AGE", 0)

    println("Received: $incomingName, Age: $incomingAge")
}

6. The Back Stack

When you launch Screen B, Screen A is not destroyed. It is paused and pushed down into the Back Stack (like a stack of plates). If the user presses the physical physical/gesture "Back" button on their phone, Android automatically "Pops" Screen B off the stack, destroying it, and revealing Screen A underneath exactly as the user left it. If you explicitly want to kill a screen via a close button in your code, you call the finish() method.
kotlin
1234
val closeButton = findViewById<Button>(R.id.closeBtn)
closeButton.setOnClickListener {
    finish() // Destroys this Activity and returns to the previous screen!
}

7. The Modern Approach: Jetpack Navigation Component

While using Intents to jump between Activities is the foundation of Android, modern enterprise applications rarely use 50 separate Activities. They use One Activity and swap out lightweight sub-screens called Fragments (which we will cover deeply in Chapter 15). To manage Fragment transitions, Google introduced the Navigation Component. It uses a visual Navigation Graph (an XML file). You can literally draw arrows between screens in Android Studio, and the component generates the transition code automatically, handling deep-links, back-stack management, and sliding animations flawlessly!

8. Mini Project: The Login Handshake

Let's build a flow where a user types their email on the Login screen and passes it to the Dashboard.

MainActivity.kt (Login):

kotlin
1234567891011
loginButton.setOnClickListener {
    val userEmail = emailEditText.text.toString()
    
    if(userEmail.isNotEmpty()) {
        val intent = Intent(this, DashboardActivity::class.java)
        intent.putExtra("EMAIL_KEY", userEmail)
        startActivity(intent)
        // We call finish() here so the user cannot hit the 'Back' button to return to the Login screen!
        finish() 
    }
}

DashboardActivity.kt:

kotlin
12345678910
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_dashboard)

    val welcomeText = findViewById<TextView>(R.id.welcomeText)
    
    // Extract the email
    val email = intent.getStringExtra("EMAIL_KEY") ?: "Guest"
    welcomeText.text = "Welcome to the Dashboard, $email!"
}

9. Common Mistakes

  • Typos in Intent Keys: If you send data using the key intent.putExtra("USERID", 5) and try to receive it using intent.getIntExtra("userid", 0), it will fail silently and return 0. Keys are strictly case-sensitive. Always define keys as global constant variables (e.g., const val EXTRAUSERID = "userid") to prevent typos.
  • Passing Massive Objects: You can pass Strings and Ints via Intents easily. Beginners often try to pass massive Lists of downloaded images or entire Custom Objects through an Intent. The app will crash with a TransactionTooLargeException. The Intent payload must remain under 1 Megabyte. Pass the *ID* of the data, and let the next screen fetch the data itself.

10. Best Practices

  • Implicit Intents for System Actions: Do not build your own Web Browser if the user just wants to view a link. Use an Implicit Intent!
kotlin
12
val webIntent = Intent(Intent.ACTION_VIEW, Uri.parse("https://google.com"))
startActivity(webIntent) // The OS will automatically open Chrome!

11. Exercises

  1. 1. Write the Kotlin code required to launch an Activity named SettingsActivity via an Explicit Intent.
  1. 2. Add an Intent Extra to the above code containing a String key THEME with a value of "DARK".

12. Coding Challenges

Challenge: Build an Implicit Intent that triggers the phone's native Share Menu (allowing the user to send a text to Twitter, WhatsApp, etc.). Research the Intent.ACTION_SEND action. Send the text: "Check out my new Android App!".

13. MCQ Quiz with Answers

Question 1

When architecting navigation between separate Activities within an Android application, what specific OS-level messaging object must be instantiated and dispatched via startActivity()?

Question 2

A developer launches Activity B from Activity A. What programmatic command must be executed within Activity A immediately following startActivity() to permanently remove Activity A from the Back Stack, preventing the user from returning via the hardware back button?

14. Interview Questions

  • Q: Explain the fundamental difference between an Explicit Intent and an Implicit Intent. In what scenario would an Implicit Intent be securely rejected by the Android OS?
  • Q: Describe the architectural mechanics of the Android "Back Stack" (Task Stack). How does the OS utilize LIFO (Last-In-First-Out) architecture to manage screen history?
  • Q: Detail the limitation of Intent Extras regarding payload size. If a developer needs to pass a massive JSON object representing 500 database entries to a new screen, what is the architecturally correct approach instead of using Intent Extras?

15. FAQs

Q: I sent an Integer using putExtra, but getStringExtra is returning null. Why? A: Data types are strictly enforced! If you put an Int, you must extract it using getIntExtra. If you put a Boolean, you must use getBooleanExtra. The extraction method must perfectly match the insertion type.

16. Summary

In Chapter 14, we shattered the boundaries of the single-screen application. We established communication with the Android OS utilizing Intents, declaring our explicit routing requirements to transition between localized Activities. We successfully transmitted parameterized state across boundaries utilizing Intent Extras, securely unpacking String and Integer payloads within localized execution contexts. Finally, we conceptualized the Back Stack, executing strict programmatic stack management via the finish() command, and previewed the single-activity architecture enforced by the modern Jetpack Navigation Component.

17. Next Chapter Recommendation

Activities are heavy, resource-intensive screens. Modern apps don't load 10 Activities; they load 1 Activity and swap out lightweight sub-sections. Proceed to Chapter 15: Fragments and Fragment Lifecycle to master modular UI architecture.

Finish this Chapter

Save your progress on your learning path and prepare for coding interview challenges.

Discussion

Join the discussion

Log in or create a free account to participate.

Sort: ·