Android Using Navigation Component And Graphs Complete Guide
Understanding the Core Concepts of Android Using Navigation Component and Graphs
Android Using Navigation Component and Graphs
Key Features of Navigation Component
- Type-Safe Arguments: When navigating between destinations (fragments or activities), you can pass data securely using type-safe arguments, preventing runtime errors associated with improper data types.
- Up Navigation and Back Stacks: The Navigation component automatically handles the back stack and up navigation, including the system back button and action bar's Up button, ensuring a consistent user experience.
- Deep Linking: You can easily set up deep links to navigate directly to specific destinations within your app from external sources such as web URLs.
- Nested Graphs and Conditional Navigation: Supports complex navigation patterns using nested graphs. Conditional navigation can also be managed, which means navigation can be controlled programmatically based on certain conditions.
- Animations and Transitions: The Navigation component facilitates easy setup and management of custom animations and transitions between different destinations.
- Support for multiple back stacks: Ideal for multi-module applications, this feature allows maintaining separate back-stacks for each module, enhancing modularity.
Setting up Navigation Component
Add Dependencies: Ensure you have added the necessary dependencies to your
build.gradle
file. Typically, these would include:implementation "androidx.navigation:navigation-fragment-ktx:2.x.x" implementation "androidx.navigation:navigation-ui-ktx:2.x.x"
Create Navigation Graph: Use XML to define your navigation graph, where each node represents a destination (activity or fragment). Edges represent the actions that navigate between those destinations. In Android Studio, you can create a navigation graph by right-clicking on the res/ directory > New > Android Resource File, then select “Navigation” as resource type.
Example of simple navigation graph:
<?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/mobile_navigation" app:startDestination="@id/navigation_home"> <fragment android:id="@+id/navigation_home" android:name="com.example.yourapplication.HomeFragment" android:label="Home"> </fragment> <fragment android:id="@+id/navigation_detail" android:name="com.example.yourapplication.DetailFragment" android:label="Detail"> </fragment> </navigation>
Set up NavigationHost and NavController: The
NavHost
typically containsFragmentContainerView
(previously known asNavHostFragment
) to host different fragments. TheNavController
is responsible for managing navigation commands. Setup is usually done in the MainActivity.Example:
<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:defaultNavHost="true" app:navGraph="@navigation/mobile_navigation" />
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment); NavigationUI.setupActionBarWithNavController(this, navController); NavigationUI.setupWithNavController(bottomNavigationView, navController);
Navigate Between Destinations: Navigate between fragments using the
NavController
. For example, from HomeFragment to DetailFragment, you might use:navController.navigate(R.id.action_navigation_home_to_navigation_detail);
Pass Data Between Destinations: Define arguments in your navigation graph.
<fragment android:id="@+id/navigation_detail" android:name="com.example.yourapplication.DetailFragment"> <action android:id="@+id/action_global_navigation_settings" app:destination="@id/navigation_settings" /> <argument android:name="userId" app:argType="integer" android:defaultValue="0"/> </fragment>
And use them in your fragments via Safe Args plugin:
val userId: Int? = arguments?.getInt("userId")
Passing data:
val action = HomeFragmentDirections.actionNavigationHomeToNavigationDetail(userId) navController.navigate(action)
Handling Up Navigation
The Navigation Component makes it straightforward to handle Up navigation by default.
@Override
public boolean onSupportNavigateUp() {
return navController.navigateUp() || super.onSupportNavigateUp();
}
Deep Linking
You can configure your navigation graph to accept deep links. Suppose you want to allow an external URL to deep link to the DetailFragment.
<fragment
android:id="@+id/navigation_detail"
android:name="com.example.yourapplication.DetailFragment"
app:deepLink="example://yourapplication/detail/{userId}">
<argument
android:name="userId"
app:argType="integer"
android:defaultValue="0"/>
</fragment>
And in your AndroidManifest.xml, define the intent filter:
<activity android:name=".MainActivity">
...
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<!-- Accepts URIs with scheme http or https -->
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Handles links that match https://yourapplication.example.com/detail/ -->
<data
android:scheme="https"
android:host="yourapplication.example.com"
android:pathPrefix="/detail/" />
</intent-filter>
</activity>
Nested Graphs and Conditional Navigation
Nested graphs are useful for modularizing your app’s navigation structure. For example, you can create separate graphs for account management, settings, and main features.
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/main_nav_graph"
app:startDestination="@id/home_dest">
<fragment
android:id="@+id/home_dest"
android:name="com.example.yourapplication.HomeFragment" />
<include app:graph="@navigation/account_nav_graph" />
</navigation>
Conditional navigation involves programmatically deciding where to navigate based on some condition.
val action =
if (isUserLoggedIn) {
HomeFragmentDirections.actionHomeToDashboard()
} else {
HomeFragmentDirections.actionHomeToLoginScreen()
}
navController.navigate(action)
Custom Animations and Transitions
Define animations and transitions in your navigation graph.
<fragment
android:id="@+id/navigation_home"
android:name="com.example.yourapplication.HomeFragment">
<action
android:id="@+id/action_navigation_home_to_navigation_detail"
app:destination="@id/navigation_detail"
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>
Alternatively, you can customize transitions using TransitionManager.
val transaction = supportFragmentManager.beginTransaction()
transaction.setCustomAnimations(
R.anim.slide_in_right,
R.anim.slide_out_left,
R.anim.slide_in_left,
R.anim.slide_out_right
)
Multiple Back Stacks
Multiple back stacks are useful in single activity architecture scenarios when the app has multiple subgraphs.
val navController = Navigation.findNavController(this, R.id.nav_host_fragment);
// Main graph
val appBarConfigurationMain = AppBarConfiguration(setOf(R.id.home_dest, R.id.dashboard_dest))
ToolbarNavigationHelper.setupWithNavController(toolbarMain, navController, appBarConfigurationMain)
// Sub graph
val appBarConfigurationSub= AppBarConfiguration(setOf(R.id.account_dest))
ToolbarNavigationHelper.setupWithNavController(toolbarSub, navController, appBarConfigurationSub)
In summary, the Android Navigation Component enhances the development process by making navigation simpler, safer, and more manageable. Its XML-based configuration approach reduces the probability of mistakes during coding, while its built-in support for type-safe arguments, deep linking, and animations ensures a robust and user-friendly application. By leveraging the capabilities of the Navigation Component, developers can efficiently build apps with intricate navigation workflows.
Online Code run
Step-by-Step Guide: How to Implement Android Using Navigation Component and Graphs
Prerequisites:
- Basic knowledge of Android development.
- Android Studio installed with an updated Android SDK.
Step 1: Create a New Project
- Open Android Studio and create a new project.
- Choose
Empty Activity
and clickNext
. - Name your application (e.g.,
NavigationComponentExample
). - Choose a package name.
- Set the
Minimum API level
to a version that suits your needs (API 21 or higher is recommended for full compatibility with Navigation Component). - Click
Finish
to create the project.
Step 2: Add Dependencies in build.gradle
Navigate to app/build.gradle
and add the following dependencies:
dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:2.5.3"
implementation "androidx.navigation:navigation-ui-ktx:2.5.3"
implementation "androidx.lifecycle:lifecycle-extensions:2.2.0"
// Add other required dependencies
}
Click Sync Now
at the top bar to sync the project with the newly added dependencies.
Step 3: Add a Navigation Graph
- In the
res
folder, create and right-click on theres
folder to then createNew > Android Resource File
. - Name the file
nav_graph
and set Resource type asNavigation
. - Ensure that the
Root Element
is set as<navigation>
. - Click
OK
.
Step 4: Design the Navigation Graph
- In the
nav_graph.xml
file, you'll see a graphical editor to design your navigation flow. - Drag and drop
Fragment
components from the palette on the left to the navigation graph. - Name each fragment (e.g.,
HomeFragment
,DetailFragment
). - Connect fragments with action arrows by clicking and dragging from one fragment to another.
- Each arrow represents an action that will navigate from the first fragment to the second.
Step 5: Create Fragments
- Right-click on the
java
folder underapp > src > main > java > com.example.navigationcomponentexample
and clickNew > Fragment > Fragment (Blank)
. - Create multiple fragments, such as
HomeFragment
andDetailFragment
.
Your fragments in the nav_graph.xml
should look something like this:
<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"
app:startDestination="@id/homeFragment">
<fragment
android:id="@+id/homeFragment"
android:name="com.example.navigationcomponentexample.HomeFragment"
android:label="HomeFragment"
tools:layout="@layout/fragment_home">
<action
android:id="@+id/action_homeFragment_to_detailFragment"
app:destination="@id/detailFragment" />
</fragment>
<fragment
android:id="@+id/detailFragment"
android:name="com.example.navigationcomponentexample.DetailFragment"
android:label="DetailFragment"
tools:layout="@layout/fragment_detail" />
</navigation>
Step 6: Update the Activity Layout
Modify the layout of the main activity (activity_main.xml
) to include a NavHostFragment
:
<androidx.constraintlayout.widget.ConstraintLayout 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">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
</androidx.constraintlayout.widget.ConstraintLayout>
Step 7: Set Up the Navigation Controller
In your MainActivity
, set up the NavController
and handle navigation actions:
import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import androidx.navigation.ui.setupActionBarWithNavController
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navController = findNavController(R.id.nav_host_fragment)
setupActionBarWithNavController(navController)
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment)
return navController.navigateUp() || super.onSupportNavigateUp()
}
}
Step 8: Design the Fragments and Add Navigation Logic
Update the views and add navigation logic in each fragment.
HomeFragment (fragment_home.xml
):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Home Fragment" />
<Button
android:id="@+id/button_to_detail"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go to Detail" />
</LinearLayout>
HomeFragment (HomeFragment.kt
):
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.fragment.findNavController
import com.example.navigationcomponentexample.R
import kotlinx.android.synthetic.main.fragment_home.*
class HomeFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_home, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
button_to_detail.setOnClickListener {
findNavController().navigate(R.id.action_homeFragment_to_detailFragment)
}
}
}
DetailFragment (fragment_detail.xml
):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Detail Fragment" />
</LinearLayout>
Step 9: Run the Application
- Click the run button in Android Studio (
Shift + F10
on Windows/Linux orControl + R
on macOS). - The application will start in the
HomeFragment
. Click the button to navigate to theDetailFragment
.
Conclusion
You've successfully created a basic Android application that uses the Navigation Component to handle navigation between fragments. This example covers creating a navigation graph, designing fragments, and setting up navigation between them using actions. You can now enhance your application by adding more fragments, passing data between them, and handling different navigation scenarios.
Top 10 Interview Questions & Answers on Android Using Navigation Component and Graphs
1. What is the Navigation Component in Android?
The Navigation Component is a part of Jetpack that simplifies the process of implementing navigation in an Android app. It helps you manage navigation graphs, deep linking, and handling navigation UI elements like the bottom navigation bar, navigation drawer, and toolbars seamlessly.
2. What are Navigation Graphs?
Navigation graphs are visual representations of the navigation paths within an Android application. They define the destinations within the app (e.g., activities, fragments) and the actions that can move a user between those destinations. Graphs are XML files that help you design and visualize navigation in your app.
3. How do I add the Navigation Component to my project?
To add the Navigation Component to your project, include the necessary dependencies in your module-level build.gradle
file:
dependencies {
def nav_version = "2.6.0" // Check for the latest version
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
}
Ensure that the Ktx libraries are included for Kotlin or use the non-Ktx version if you're working with Java.
4. How do I create a new navigation graph in Android Studio?
To create a new navigation graph:
- Open your project in Android Studio.
- In the
res
folder, right-click and choose New > Android Resource File. - Name the file, choose Resource type as Navigation, and click OK.
- A new XML file will open representing the navigation graph.
5. How do you add destinations to a navigation graph?
Destinations in a navigation graph can be added by dragging activities or fragments from the Project pane or by right-clicking the graph and selecting Add Destination. You can also manually add them in XML:
<fragment
android:id="@+id/firstFragment"
android:name="com.example.myapp.FirstFragment"
android:label="Fragment 1" />
6. What are actions within a navigation graph, and how are they used?
Actions describe how you navigate from one destination to another. They are represented by <action>
tags in the navigation graph XML:
<fragment
android:id="@+id/firstFragment"
android:name="com.example.myapp.FirstFragment">
<action
android:id="@+id/action_firstFragment_to_secondFragment"
app:destination="@id/secondFragment" />
</fragment>
You can navigate to the destination using the specified action ID.
7. How do I handle deep linking in a navigation graph?
Deep linking allows users to navigate directly to a specific destination within your app based on a URL. It can be added to the navigation graph XML:
<fragment
android:id="@+id/detailFragment"
android:name="com.example.myapp.DetailFragment">
<argument
android:name="orderId"
app:argType="integer"/>
<deepLink app:uri="example://myapp.com/detail/{orderId}" />
</fragment>
Ensure your URI matches the pattern expected, and you handle the argument correctly in the destination.
8. How do you manage navigation between fragments using ViewModel?
Using ViewModel, you can manage UI-related data in a lifecycle-conscious way. This helps in maintaining state during configuration changes. For navigation, ViewModel can be used to store navigation-related state or communicate between fragments:
class SharedViewModel : ViewModel() {
val navigateToSecondFragment = MutableLiveData<Boolean>()
}
In your FirstFragment
:
sharedViewModel.navigateToSecondFragment.observe(viewLifecycleOwner, Observer { navigate ->
if (navigate) {
findNavController().navigate(R.id.action_firstFragment_to_secondFragment)
sharedViewModel.navigateToSecondFragment.value = false
}
})
9. How do you navigate using Safe Args?
Safe Args is a Gradle plugin that generates code for type-safe navigation with arguments:
- Add the Safe Args plugin in your module-level
build.gradle
file:
apply plugin: "androidx.navigation.safeargs.kotlin"
- In your navigation graph, define arguments:
<fragment
android:id="@+id/detailFragment"
android:name="com.example.myapp.DetailFragment">
<argument
android:name="orderId"
app:argType="integer"/>
</fragment>
- Use the generated
Directions
class to navigate:
val action = FirstFragmentDirections.actionFirstFragmentToSecondFragment(orderId)
findNavController().navigate(action)
10. What are some best practices when using Navigation Component?
Some best practices for using the Navigation Component include:
- Organize your destinations and actions to make your navigation graph easily understandable.
- Use ViewModel for state management to ensure data persistence and proper communication between fragments or activities.
- Utilize Safe Args for type-safe navigation with arguments.
- Handle deep linking appropriately to provide seamless user experience.
- Leverage NavigationUI for managing navigation UI components like toolbars and bottom navigation.
Login to post a comment.