Mobile Development 13 min read

Understanding Android Jetpack Navigation: Setup, Usage, Data Passing, Deep Links, and Source Code Analysis

This article provides a comprehensive guide to Android Jetpack's Navigation component, covering its purpose, setup with Gradle, XML graph configuration, fragment navigation code, data passing methods, deep‑link handling, and an analysis of its underlying source classes such as NavHostFragment and NavController.

JD Tech
JD Tech
JD Tech
Understanding Android Jetpack Navigation: Setup, Usage, Data Passing, Deep Links, and Source Code Analysis

Author : Qiu Junjie – Senior Android Engineer with over 5 years of development experience, responsible for JD.com product detail development.

Introduction : At Google I/O 2018, Android Jetpack was announced, consolidating components like Lifecycle, LiveData, Room, and ViewModel into a unified architecture. Among the new components, Navigation provides a visual, type‑safe way to manage fragment stacks, deep links, and argument passing.

Why use Navigation?

Simplifies fragment stack management and eliminates IllegalStateException.

Supports deep links that can jump directly to a fragment, bypassing activities.

Provides safer parameter transmission.

Setup (add to build.gradle ):

dependencies {
    nav_version = '1.0.0-alpha01'
    implementation "android.arch.navigation:navigation-fragment:$nav_version"
    implementation "android.arch.navigation:navigation-ui:$nav_version"
}

Navigation Graph (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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/mainFragment">
    <fragment
        android:id="@+id/mainFragment"
        android:name="com.jd.demo.ui.main.MainFragment"
        android:label="main_fragment"
        tools:layout="@layout/main_fragment_2">
        <action
            android:id="@+id/action_to_mainFragment2"
            app:destination="@+id/mainFragment2"
            app:enterAnim="@anim/slide_in_right"
            app:exitAnim="@anim/slide_out_left"
            app:popEnterAnim="@anim/slide_in_left"
            app:popExitAnim="@anim/slide_out_right" />
    </fragment>
    <fragment
        android:id="@+id/mainFragment2"
        android:name="com.jd.demo.ui.main.MainFragment2"
        android:label="main_fragment_2"
        tools:layout="@layout/main_fragment_2" />
</navigation>

Activity Layout (activity_main.xml) :

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">
    <fragment
        android:id="@+id/my_nav_host_fragment"
        android:name="androidx.navigation.fragment.NavHostFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:defaultNavHost="true"
        app:navGraph="@navigation/nav_graph" />
</LinearLayout>

Fragment Navigation Code (MainFragment.kt) :

val view = inflater.inflate(R.layout.main_fragment_3, container, false)
val button1 = view.findViewById<Button>(R.id.button3)
button1.setOnClickListener { v ->
    Navigation.findNavController(v).navigate(R.id.action_mainFragment2_to_mainFragment1)
}
return view

Navigating to a Destination – four possible calls:

Navigation.findNavController(Activity, @IdRes Int viewId)

Navigation.findNavController(View)

NavHostFragment.findNavController(Fragment)

View.findNavController()

Example: Navigation.findNavController(view).navigate(R.id.action_mainFragment2_to_mainFragment1)

Passing Data

1) Using a Bundle :

Bundle bundle = new Bundle();
 bundle.putString("amount", amount);
 Navigation.findNavController(view).navigate(R.id.confirmationAction, bundle);

Retrieve in the target fragment with getArguments().getString("amount") .

2) Using Safe Args (type‑safe): Add the plugin to build.gradle :

apply plugin: 'com.android.application'
apply plugin: 'androidx.navigation.safeargs'

Define argument in the fragment XML:

<fragment
    android:id="@+id/confirmationFragment"
    android:name="com.example.buybuddy.ConfirmationFragment"
    android:label="fragment_confirmation"
    tools:layout="@layout/fragment_confirmation">
    <argument android:name="amount" android:defaultValue="1" app:type="integer" />
</fragment>

Pass data:

EditText amountTv = getView().findViewById(R.id.editTextAmount);
int amount = Integer.parseInt(amountTv.getText().toString());
ConfirmationAction action = ConfirmationFragmentDirections.confirmationAction();
action.setAmount(amount);
Navigation.findNavController(view).navigate(action);

Receive data:

int amount = ConfirmationFragmentArgs.fromBundle(getArguments()).getAmount();
textView.setText(String.valueOf(amount));

Deep Link Support

Define deep links inside a fragment node:

<deepLink app:uri="www.jd.com" />
<deepLink app:uri="www.jd.com.*" />
<deepLink app:uri="www.jd.com/{myarg}" android:autoVerify="true" />

Configure the host activity:

<activity android:name=".MainActivity">
    <nav-graph android:value="@navigation/xxxxx" />
</activity>

Retrieve the argument in the fragment:

String myArg = getArguments().getString("myarg");

Source Code Analysis

NavHostFragment provides a container for navigation and implements NavHost . In onCreate it creates a NavController and registers a FragmentNavigator :

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Context context = getContext();
    mNavController = new NavController(context);
    mNavController.getNavigatorProvider().addNavigator(createFragmentNavigator());
}

onCreateView returns a FrameLayout that serves as the navigation host:

@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    FrameLayout frameLayout = new FrameLayout(inflater.getContext());
    frameLayout.setId(getId());
    return frameLayout;
}

onViewCreated attaches the NavController to the root view via a tag, enabling Navigation.findNavController(view) to locate the controller:

@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
    super.onViewCreated(view, savedInstanceState);
    if (!(view instanceof ViewGroup)) {
        throw new IllegalStateException("created host view " + view + " is not a ViewGroup");
    }
    View rootView = view.getParent() != null ? (View) view.getParent() : view;
    Navigation.setViewNavController(rootView, mNavController);
}

public static void setViewNavController(@NonNull View view, @Nullable NavController controller) {
    view.setTag(R.id.nav_controller_view_tag, controller);
}

NavController parses the nav_graph.xml via NavInflater , builds a graph of NavDestination objects, and manages the back stack. Navigator is an abstract class; concrete implementations such as FragmentNavigator and ActivityNavigator perform the actual navigation actions.

Conclusion

The Navigation component offers a powerful, safe, and visual way to handle fragment navigation, deep links, and data passing, integrating seamlessly with other Jetpack libraries like Lifecycle and ViewModel. Kotlin extensions (KTX) further simplify usage, making it essential for modern Android development.

Mobile DevelopmentAndroidKotlinnavigationDeep LinkJetpackSafe Args
JD Tech
Written by

JD Tech

Official JD technology sharing platform. All the cutting‑edge JD tech, innovative insights, and open‑source solutions you’re looking for, all in one place.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.