Free tutorials & notes in Hindi & English · Clean code examples 🧰 Free PDF & Image Tools →
📋 Screens, Lists & Navigation  ·  Lesson 25

Navigation Component & Safe Args

Why the Navigation Component?

Manual FragmentManager

  • replace() + addToBackStack everywhere
  • Back stack bugs
  • Toolbar title by hand
  • Bundles with string keys

Navigation Component

  • All screens in one graph
  • Back and Up handled
  • Toolbar, drawer, bottom nav auto-linked
  • Type-safe arguments (Safe Args)
Less code, fewer bugs

Dependencies

TOML + Kotlin DSL
# gradle/libs.versions.toml
navigation = "2.8.5"
androidx-navigation-fragment-ktx = { group = "androidx.navigation", name = "navigation-fragment-ktx", version.ref = "navigation" }
androidx-navigation-ui-ktx = { group = "androidx.navigation", name = "navigation-ui-ktx", version.ref = "navigation" }

// app/build.gradle.kts
implementation(libs.androidx.navigation.fragment.ktx)
implementation(libs.androidx.navigation.ui.ktx)

The navigation graph

Right-click res → New → Android Resource File → type Navigation → nav_graph. The Design view shows screens as boxes and actions as arrows. This is the real graph of Student Diary:

XML – res/navigation/nav_graph.xml
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/nav_graph"
    app:startDestination="@id/notesFragment">

    <!-- Open the editor from anywhere (FAB, list item) -->
    <action
        android:id="@+id/action_global_editor"
        app:destination="@id/editorFragment"
        app:enterAnim="@anim/nav_default_enter_anim"
        app:exitAnim="@anim/nav_default_exit_anim"
        app:popEnterAnim="@anim/nav_default_pop_enter_anim"
        app:popExitAnim="@anim/nav_default_pop_exit_anim" />

    <fragment
        android:id="@+id/notesFragment"
        android:name="com.codingeasily.studentdiary.ui.notes.NotesFragment"
        android:label="@string/app_name" />

    <!-- The same list fragment, reused with different arguments -->
    <fragment
        android:id="@+id/favoritesFragment"
        android:name="com.codingeasily.studentdiary.ui.notes.NoteListFragment"
        android:label="@string/menu_favourites">
        <argument
            android:name="filter"
            android:defaultValue="FAVORITES"
            app:argType="string" />
    </fragment>

    <fragment
        android:id="@+id/subjectsFragment"
        android:name="com.codingeasily.studentdiary.ui.subjects.SubjectsFragment"
        android:label="@string/menu_subjects">
        <action
            android:id="@+id/action_subjects_to_subjectNotes"
            app:destination="@id/subjectNotesFragment" />
    </fragment>

    <fragment
        android:id="@+id/subjectNotesFragment"
        android:name="com.codingeasily.studentdiary.ui.notes.NoteListFragment"
        android:label="{subject}">
        <argument
            android:name="filter"
            android:defaultValue="SUBJECT"
            app:argType="string" />
        <argument
            android:name="subject"
            app:argType="string" />
    </fragment>

    <fragment
        android:id="@+id/statsFragment"
        android:name="com.codingeasily.studentdiary.ui.stats.StatsFragment"
        android:label="@string/menu_stats" />

    <fragment
        android:id="@+id/settingsFragment"
        android:name="com.codingeasily.studentdiary.ui.settings.SettingsFragment"
        android:label="@string/menu_settings" />

    <fragment
        android:id="@+id/helpFragment"
        android:name="com.codingeasily.studentdiary.ui.help.HelpFragment"
        android:label="@string/menu_help" />

    <fragment
        android:id="@+id/editorFragment"
        android:name="com.codingeasily.studentdiary.ui.editor.AddEditNoteFragment"
        android:label="@string/note">
        <argument
            android:name="noteId"
            android:defaultValue="-1L"
            app:argType="long" />
    </fragment>
</navigation>
notesFragmentstartaction_global_editoreditorFragmentarg noteId: long
Global action: reachable from every screen
subjectsFragmentaction_subjects_to_subjectNotessubjectNotesFragmentargs filter, subject
Normal action between two screens

NavHostFragment

XML
<!-- activity_main.xml (Student Diary, part) -->
<androidx.fragment.app.FragmentContainerView
    android:id="@+id/nav_host"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    app:defaultNavHost="true"
    app:navGraph="@navigation/nav_graph" />

app:defaultNavHost="true" lets the system Back button go back inside the graph.

Kotlin
// Student Diary – NoteListFragment: open the editor for a note
findNavController().navigate(R.id.action_global_editor, bundleOf("noteId" to note.id))

// MainActivity – FAB opens an empty editor (noteId keeps its default -1L)
binding.fab.setOnClickListener { navController.navigate(R.id.action_global_editor) }

// SubjectsFragment – open notes of one subject
findNavController().navigate(
    R.id.action_subjects_to_subjectNotes,
    bundleOf("filter" to "SUBJECT", "subject" to item.subject)
)

// Go back
findNavController().navigateUp()

Arguments (Bundle way)

Kotlin
// AddEditNoteFragment
val noteId = arguments?.getLong("noteId", -1L) ?: -1L
if (noteId != -1L) loadNote(noteId) else showEmptyForm()

Default values from the graph (like -1L) are used when the caller passes nothing.

Safe Args (type-safe way)

Kotlin DSL – add the plugin
// build.gradle.kts (root)
plugins {
    // ...
    id("androidx.navigation.safeargs.kotlin") version "2.8.5" apply false
}

// app/build.gradle.kts
plugins {
    // ...
    id("androidx.navigation.safeargs.kotlin")
}
Kotlin – generated Directions and Args
// nav_graph.xml has the global action  action_global_editor  →  editorFragment
// and editorFragment declares <argument android:name="noteId" app:argType="long" android:defaultValue="-1L"/>

// Generated for global actions: NavGraphDirections (named after the graph id "nav_graph")
val action = NavGraphDirections.actionGlobalEditor(noteId = note.id)
findNavController().navigate(action)

// Generated for the destination class: AddEditNoteFragmentArgs
private val args: AddEditNoteFragmentArgs by navArgs()
val noteId: Long = args.noteId        // a Long – checked by the compiler

Toolbar Up button

Kotlin – MainActivity
// MainActivity (Student Diary)
val navHost = supportFragmentManager.findFragmentById(R.id.nav_host) as NavHostFragment
navController = navHost.navController
appBarConfiguration = AppBarConfiguration(topLevelIds, binding.drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)   // title + ← / ☰

override fun onSupportNavigateUp(): Boolean =
    navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()

// react to screen changes (hide bottom bar on the editor)
navController.addOnDestinationChangedListener { _, destination, _ ->
    binding.bottomNav.isVisible = destination.id in bottomScreens
}
9:41▮▮ 85%☰Student Diary⋮Maths homeworkHigh📝Notes📚Subjects📊Progress9:41▮▮ 85%←Note⋮TitleDetailsSAVE NOTE
Top-level screen shows ☰; editor shows ← and hides the bottom bar

Common mistakes

  • Menu item ids that do not match destination ids → bottom nav / drawer clicks do nothing.
  • Calling navigate() twice quickly (double tap) → "navigation destination is unknown" crash. Ignore extra clicks or check the current destination.
  • Forgetting onSupportNavigateUp → the ← button does nothing.
  • Wrong default format for long arguments → write -1L.

Summary

  • nav_graph.xml lists destinations, actions and arguments.
  • NavHostFragment hosts the screens; findNavController().navigate(id, bundle) moves between them.
  • Safe Args generates type-safe Directions/Args; setupActionBarWithNavController handles titles and Up.
✅ Practice

Convert your fragment demo to a nav graph: Home → Details (argument: subject) → Edit. Add Safe Args and an enter/exit animation to the actions.

Frequently Asked Questions

What is a destination?
A screen in the navigation graph, usually a fragment. Each destination has an id that you navigate to.
Is Safe Args required?
No. You can pass a Bundle with bundleOf(). Safe Args generates classes so the compiler checks argument names and types, which prevents typos.
How do I go back in code?
Call findNavController().navigateUp() or popBackStack(). Both return to the previous destination.
← Android Tutorial (Kotlin)
🔗

Share this topic with a friend

यह topic किसी दोस्त को भेजें

Found it useful? Send it to a classmate learning the same thing.

अच्छा लगा? जो दोस्त यही सीख रहा है, उसे भेज दीजिए।

Next topicBottom Navigation View Your progress: 25 / 43 (58%) · Lesson 26 / 43 Continue →

How was this lesson?

Your feedback helps us make the content better.

Write a review or suggestion (optional)

After approval, your name and city may appear publicly with your review. Please do not write your email or phone number.

▶ CodingEasily on YouTube

Learn with video lessons in easy Hindi

Featured video: RDBMS Part 3 – Class XI Commerce IT

▶ Subscribe – it’s free