Navigation Component for Android Part 2: Graphs and Deep Links
In this tutorial you’ll use the Jetpack Navigation component to write an Android app utilizing graphs and deep links to navigate through different screens. By Meng Taing.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Navigation Component for Android Part 2: Graphs and Deep Links
30 mins
- Getting Started
- Adding Dependencies
- Inflating Layout to Fragment in AndroidX
- Building Graphs With the Navigation Component
- Adding NavHostFragment With Navigation Component Graph
- Setting up Navigation Component in MainActivity
- Connecting Toolbar, Drawer and Navigation Controller
- Navigating From Drawer Menu Items
- Navigating From Floating Action Button
- Showing DialogFragment
- ViewModel Across Navigation Graph
- Getting ViewModel in Activity From Navigation Graph
- Getting ViewModel in Fragment From Navigation Graph
- Creating Your First Love Letter
- Building Notification With Explicit Deep Link
- Passing Letter With Safe Args
- Getting Letter From Safe Args
- Seeing What You’ve Sent
- Seeing What You’ve Received
- Nested Graph
- Creating Implicit Deep Link With URI
- Handling Web URL Deep Link
- Where to Go From Here?
Navigation between Fragments using the FragmentManager is a nightmare most Android developers try to avoid. Usually, the Fragment lifecycle doesn’t play well with the Activity lifecycle.
Managing the Fragment back stack is another headache, especially when you add deep links to the mix. At Google I/O ’18, Jetpack Navigation component came to the rescue. The Navigation component takes the responsibility of the FragmentManager so developers can focus on building awesome features in their apps.
Some of the features in the Navigation component Version 1.0.0 were already covered in The Navigation Architecture Component Tutorial: Getting Started. In this tutorial, you’ll learn about these cool Jetpack Navigation component 2.1.0 features:
- DialogFragment in navigation graph.
- ViewModel per navigation graph.
- Safe Args.
- Nested graph.
- Explicit and implicit deep links.
There’s also an awesome Jetpack Navigation Controller screen cast which quickly walks you through how to build a navigation graph. Be sure to check them out.
There’s also an awesome Jetpack Navigation Controller screen cast which quickly walks you through how to build a navigation graph. Be sure to check them out.
To embark on a romantic navigation journey, you’ll build a Love Letter app. As you might guess from the name, this app allows lets you send and receive love letters.
Getting Started
Some of the Navigation component features in this tutorial require Android Studio 3.4 or higher. Make sure to install the latest stable release.
First, download the materials for this tutorial using the Download materials button at the top or bottom of this tutorial. Open the project with Android Studio. You’ll be prompted with a dialog to choose Gradle wrapper:
Click OK. You’ll find the project structure looks like this:
Take a look at the fragments package:
- InboxFragment: List of letters you received.
- SentFragment: List of letters you sent.
- CreateLetterFragment: Where you compose and send your letter.
- PresentationFragment: Where you view the content of the letter.
- EditProfileFragment: Dialog for inputting your name and email address.
There are two additional Fragments inside the agreement package:
- PrivacyPolicyFragment: Long, boring text for the privacy policy nobody cares about.
- TermsOfServiceFragment: More long, boring text for the terms of service nobody bothers to read.
Here are other important classes:
- LetterAdapter: RecyclerView adapter for list of letters.
- LetterPagerAdapter: ViewPager adapter for letter presentation.
- Event: LiveData value wrapper that makes observer read its value only once.
- KotlinExtension: Contains a few short-handed functions to make the code cleaner.
- LetterRepository: Repository class for Letter CRUD operations.
- LetterViewModel: The only ViewModel in this app for MainActivity and other Fragments.
- MainActivity: The single Activity where navigation is setup.
To make sure everything is compatible and working, run the app. You should see an empty screen like this:
The floating action button with the envelope icon is like the Compose button on Gmail app. It’ll bring you to the CreateLetterFragment.
Slide from the left edge to view the navigation drawer. All the drawer menu items are setup for you:
Adding Dependencies
Open build.gradle under app module. Add the following code into dependencies
braces below // TUTORIAL DEPENDENCIES
:
def nav_version = "2.1.0"
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
Run Gradle sync through Android Studio. If there aren’t any errors, you’re good to go.
Inflating Layout to Fragment in AndroidX
Because you added androidx.navigation:navigation-fragment-ktx
, you’re now able to set the layout for the Fragment directly in its constructor. Open the following five files one at a time, and add the layout id to each constructor:
//InboxFragment.kt
class InboxFragment : Fragment(R.layout.fragment_inbox)
//SentFragment.kt
class SentFragment : Fragment(R.layout.fragment_sent)
//PresentationFragment.kt
class PresentationFragment : Fragment(R.layout.fragment_presentation)
//PrivacyPolicyFragment.kt
class PrivacyPolicyFragment : Fragment(R.layout.fragment_privacy_policy)
//TermsOfServiceFragment.kt
class TermsOfServiceFragment : Fragment(R.layout.fragment_terms_of_service)
The benefit of this approach and setting the layout in the Fragment constructor is that you don’t have to override onCreateView()
and write boilerplate code to inflate the layout and return it.
Building Graphs With the Navigation Component
Right click the res folder in Project Explorer, then create a new Directory named navigation. Right click the navigation folder and create a new Navigation resource file named nav_graph. You’ll be brought to the Navigation Editor:
Add the following five fragments and the agreement graph to the editor. Connect them as in the screenshot below:
- InboxFragment, set as home fragment.
- SentFragment.
- CreateLetterFragment.
- PresentationFragment.
- EditProfileFragment, shown as a dialog.
You only need to connect the action from InboxFragment and SentFragment to PresentationFragment. You’ll find out why in the Safe Args section below.
Switch the view mode from Design to Text. Fill in navigation id
, action id
and fragment label
. Then, fill in layout
as the code below, or simply copy and paste:
<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/inboxFragment">
<fragment
android:id="@+id/inboxFragment"
android:name="com.raywenderlich.android.loveletter.fragment.InboxFragment"
android:label="@string/menu_inbox"
tools:layout="@layout/fragment_inbox">
<action
android:id="@+id/presentLetter"
app:destination="@id/presentationFragment"/>
</fragment>
<fragment
android:id="@+id/sentFragment"
android:name="com.raywenderlich.android.loveletter.fragment.SentFragment"
android:label="@string/menu_sent"
tools:layout="@layout/fragment_sent">
<action
android:id="@+id/presentLetter"
app:destination="@id/presentationFragment"/>
</fragment>
<fragment
android:id="@+id/createLetterFragment"
android:name="com.raywenderlich.android.loveletter.fragment.CreateLetterFragment"
android:label="@string/create_letter"
tools:layout="@layout/fragment_create_letter"/>
<dialog
android:id="@+id/editProfileFragment"
android:name="com.raywenderlich.android.loveletter.fragment.EditProfileFragment"
android:label="@string/edit_profile"
tools:layout="@layout/fragment_edit_profile"/>
<fragment
android:id="@+id/presentationFragment"
android:name="com.raywenderlich.android.loveletter.fragment.PresentationFragment"
android:label="@string/presentation"
tools:layout="@layout/fragment_presentation"/>
</navigation>
<dialog>
tag is used instead of <fragment>
for EditProfileFragment, otherwise the fragment would take up the full space on the screen.If the fragments in Navigation Editor don’t render any layout, make sure that the tools:layout
attributes are added. You could also simply rebuild the project.
You’ve finished building the navigation graphs. Now you’re ready to use nav_graph in content_main.xml.
Adding NavHostFragment With Navigation Component Graph
Open content_main.xml and add the following code inside the ConstraintLayout
:
<fragment
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="@navigation/nav_graph"/>
What you should notice here:
-
android:name="androidx.navigation.fragment.NavHostFragment"
: You’re using NavHostFragment from Androidx to host your navigation graph. -
app:navGraph="@navigation/nav_graph"
: You’re supplying your navigation graph to the NavHostFragment.
Now it’s time to let your MainActivity know about the NavHostFragment and navigation graph.
Setting up Navigation Component in MainActivity
Open MainActivity.kt and examine the code. You’ll see some code for navigation drawer and data binding is already there. Data binding binds the profile name and email to the navigation drawer header.
There are a bunch of TODO
s to help you know where to insert the code snippets.
Right below the MainActivity
class declaration, add the following two private fields:
private val navController by lazy { findNavController(R.id.nav_host_fragment) } //1
private val appBarConfiguration by lazy {
AppBarConfiguration(
setOf(
R.id.sentFragment,
R.id.inboxFragment
), drawerLayout
)
} //2
Here’s what you did:
- You’ll use
navController
to navigate from one fragment to another. ImportfindNavController
fromandroidx.navigation.findNavController.
-
appBarConfiguration
defines which fragments are the top level fragments so the drawerLayout and hamburger icon can work properly. You’ll understand why when you run the app.