Navigation Component (Java)
The Navigation Component replaces manual FragmentTransaction code with a declarative nav graph, a NavHostFragment container, and a NavController that handles back stack, transitions, and Up behavior. With Safe Args you also get type-safe argument passing in Java.
Why Use It?
Declarative Graph
All destinations & actions in one XML
Back/Up handled
Correct behavior out-of-the-box
Safe Args
Type-safe arguments in Java
Deep Links
Open screens from URLs/notifications
Setup (Gradle)
// Project build.gradle (settings may vary)
buildscript {
dependencies {
classpath 'androidx.navigation:navigation-safe-args-gradle-plugin:2.7.7'
}
}
// Module: app/build.gradle
plugins {
id 'com.android.application'
id 'androidx.navigation.safeargs' // Java Safe Args
}
dependencies {
implementation 'androidx.navigation:navigation-fragment:2.7.7'
implementation 'androidx.navigation:navigation-ui:2.7.7'
implementation 'com.google.android.material:material:1.12.0'
}
Create the Nav Host
Add a NavHostFragment container (usually in your Activity layout). It swaps in/out destination fragments.
<!-- res/layout/activity_main.xml -->
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:navGraph="@navigation/nav_graph"
app:defaultNavHost="true" />
Build the Navigation Graph
<!-- res/navigation/nav_graph.xml -->
<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/firstFragment">
<fragment
android:id="@+id/firstFragment"
android:name="com.example.FirstFragment"
android:label="First">
<!-- Type-safe argument for destination -->
<argument android:name="userName"
app:argType="string"
android:defaultValue="Guest"/>
<!-- Action to navigate to SecondFragment -->
<action
android:id="@+id/action_first_to_second"
app:destination="@id/secondFragment"
app:popUpTo="@id/firstFragment"
app:popUpToInclusive="false" />
</fragment>
<fragment
android:id="@+id/secondFragment"
android:name="com.example.SecondFragment"
android:label="Second" />
</navigation>
MainActivity: App Bar + Up Button
// MainActivity.java
public class MainActivity extends AppCompatActivity {
private AppBarConfiguration appBarConfiguration;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar); // if using a Toolbar
setSupportActionBar(toolbar);
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
appBarConfiguration = new AppBarConfiguration.Builder(navController.getGraph()).build();
NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration);
}
@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
return NavigationUI.navigateUp(navController, appBarConfiguration) || super.onSupportNavigateUp();
}
}
Navigating in Java (with Safe Args)
Inside FirstFragment, create a click listener that navigates to SecondFragment with a typed argument.
// FirstFragment.java
NavController nav = NavHostFragment.findNavController(this);
// Using generated Directions class:
FirstFragmentDirections.ActionFirstToSecond action =
FirstFragmentDirections.actionFirstToSecond();
action.setUserName("Sonu");
nav.navigate(action);
In SecondFragment, read the argument safely:
// SecondFragment.java
SecondFragmentArgs args = SecondFragmentArgs.fromBundle(getArguments());
String name = args.getUserName(); // "Sonu"
NavigationUI with BottomNavigationView
Hook your bottom nav to the controller and declare top-level destinations (no Up arrow among them).
<!-- res/layout/activity_main.xml (excerpt) -->
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottom_nav"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:menu="@menu/menu_bottom" />
// MainActivity.java (after navController creation)
BottomNavigationView bottom = findViewById(R.id.bottom_nav);
NavigationUI.setupWithNavController(bottom, navController);
appBarConfiguration = new AppBarConfiguration.Builder(
R.id.homeFragment, R.id.searchFragment, R.id.profileFragment // top-level IDs
).build();
Deep Links
Open screens via URLs/intent filters. Add a deep link to a destination:
<!-- In nav_graph destination -->
<deepLink app:uri="https://codingwithsonu.com/user/{userId}" />
And in the manifest for NavHostActivity (your activity):
<activity android:name=".MainActivity"
android:exported="true">
<nav-graph android:value="@navigation/nav_graph" />
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https"
android:host="codingwithsonu.com" />
</intent-filter>
</activity>
Pop Behavior & Back Stack Control
| Property / Flag | Effect | When to Use |
|---|---|---|
| popUpTo | Pop stack up to a destination | Clear intermediate screens |
| popUpToInclusive | Include the target in the pop | Reset to root/home |
| app:launchSingleTop | Avoid multiple copies on top | Idempotent navigations |
Custom Animations (optional)
<action ...
app:enterAnim="@anim/slide_in_right"
app:exitAnim="@anim/slide_out_left"
app:popEnterAnim="@anim/slide_in_left"
app:popExitAnim="@anim/slide_out_right" />
Manual Transactions vs Navigation
| Aspect | Manual FragmentTransaction | Navigation Component |
|---|---|---|
| Back stack | Dev must manage | Managed by graph/controller |
| Args | Bundles (unsafe types) | Safe Args (generated classes) |
| Deep links | Manual parsing | Built-in destinations |
| Up button | Manual | NavigationUI handles |
| Transitions | Manual anim logic | Per-action attributes |
Dialog Destinations
You can add a <dialog> destination (DialogFragment) in the graph and navigate to it like any other destination.
Troubleshooting
“No NavController set” ➜ Ensure your container is NavHostFragment and you call Navigation.findNavController(activity, R.id.nav_host_fragment) or NavHostFragment.findNavController(fragment).
Args class not found ➜ Rebuild project; confirm Safe Args plugin applied and res/navigation/ graph exists.
Up button weird ➜ Make destinations top-level in AppBarConfiguration or remove incorrect popUpTo rules.
Multiple copies on back stack ➜ Use app:launchSingleTop="true" on the action.
Hands-On Exercise
- Create FirstFragment and SecondFragment with an action and an argument (userName).
- Navigate via a button in First; show the name in Second using SecondFragmentArgs.
- Add a third fragment and use popUpTo to clear intermediate screens.
- Attach a BottomNavigationView to 3 top-level fragments via NavigationUI.