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.

Leave a rating/review
Download materials
Save for later
Share
You are currently viewing page 3 of 4 of this article. Click here to view the first page.

Creating Your First Love Letter

Open CreateLetterFragment.kt and replace the declaration of lettersViewModel with the following code:

private val lettersViewModel: LettersViewModel by navGraphViewModels(R.id.nav_graph)

Once again, it’s the same line to get the instance of the same ViewModel.

In the Create Letter Fragment, you might have noticed there are two option menu items:

  • PUSH: Create a local push notification. This mimics the notification the app sends when your recipient receives your letter. In this tutorial, you’ll only send love letters to yourself.
  • SEND: Create a web URI for a deep link. The URI is supposed to be embedded in the love letter email. If the recipient also has the Love Letter app installed on his or her phone, when he or she clicks the URI in the email app, the phone should launch the Love Letter app to handle the deep link.

When you click SEND or PUSH, handleSend gets called. Take a look at handleSend.

private fun handleSend(toSend: () -> Unit) {
  if (lettersViewModel != null && lettersViewModel.hasFullProfile()) {
    toSend()
    // TODO: navigate to sent fragment

  } else {
    // TODO: navigate to edit profile fragment

  }
  hideKeyboard()
}

handleSend is checking if there is any profile information. It’s making sure the name and email aren’t empty.

If there is profile information, invoke toSend lambda and navigate to SentFragment. Otherwise, show EditProfileFragment dialog.

Based on this logic, replace the implementation of handleSend with the following code:

if (lettersViewModel.hasFullProfile()) {
  toSend()
  findNavController().popBackStack(R.id.inboxFragment, false)  //1
  findNavController().navigate(R.id.sentFragment)  //2
} else {
  findNavController().navigate(R.id.editProfileFragment)  //3
}
hideKeyboard()

Here’s a breakdown of the code above:

The work around here is to go back to InboxFragment, which is the home fragment, first.

  1. In a fragment, call findNavController() to get the navigation controller. After you’ve done your sent action, exit CreateLetterFragment and go to SentFragment to see what you’ve sent. You can’t popBackStack directly to SentFragment because it might not be in the navigation stack.

    The work around here is to go back to InboxFragment, which is the home fragment, first.

  2. Here you go to SentFragment from InboxFragment.
  3. If the app doesn’t have profile information, go to EditProfileFragment.
Note: There are a few variants of findNavController(). Make sure to import the one under androidx.navigation.fragment.

Before you can test the PUSH function, you need to learn about how to generate a push notification with deep link.

Building Notification With Explicit Deep Link

There are two types of deep links:

  • Explicit: An explicit deep link is a single instance of a deep link that uses a PendingIntent to take users to a specific location within your app.
  • Implicit: An implicit deep link is a URI that refers to a specific destination in an app.

Open NotificationHelper.kt. Examine the code and you’ll find three methods:

  1. sendLocalNotification: Gets notificationManager from context and sends the notification.
  2. sendLocalNotification: Builds a notification from the letter object.
  3. buildPendingIntentFromNavigation: Builds a pending intent to navigate to specific fragment when notification banner is clicked.

There’s no implementation inside buildPendingIntentFromNavigation yet. Replace the code inside buildPendingIntentFromNavigation with the code below:

val bundle = Bundle()
bundle.putString(EXTRA_LETTER, gson.toJson(letter))  //1
return NavDeepLinkBuilder(context)  //2
  .setGraph(R.navigation.nav_graph)  //3
  .setDestination(R.id.presentationFragment)  //4
  .setArguments(bundle)  //4
  .createPendingIntent()  //5

Here you:

  1. Create the bundle which contains the serialized letter string.
  2. Use NavDeepLinkBuilder to build a pending intent.
  3. Pass in your navigation graph resource id.
  4. Pass in your fragment ID in navigation graph.
  5. Generate the pending intent. Done!

Run the app and send your first love letter. Go to the create letter screen from the floating action button. Write a message to your loved one and click the PUSH button.

You should see a push notification on the top of your screen. Clicking the notification won’t work because you haven’t configured the PresentationFragment.

Push Notification

Create another letter and click the SEND button. Observe the Logcat in Android Studio. You’ll see a link like this:

Logcat of Sent Message

http://www.loveletter.com/letter/%7B%22description%22%3A%22This+is+Romeo.+Long+time+no+see.+How+are+you%3F%22%2C%22from%22%3A%22romeo%40loveletter.com%22%2C%22fromName%22%3A%22Romeo%22%2C%22ps%22%3A%22I+love+you%22%2C%22sentAt%22%3A1565102907743%2C%22title%22%3A%22My+First+Love+Letter%22%2C%22to%22%3A%22juliette%40loveletter.com%22%2C%22uid%22%3A1565102907743%7D

You’ll use this link for the implicit deep link implementation in a later section.

What if you haven’t filled in your profile information? If you already have profile information, click the edit profile button from the drawer header, clear the name and email field and click SAVE.

Now go back to create letter screen, click either the PUSH or SEND button. You’ll see the edit profile dialog! This is really cool because you can reuse the dialog with one line of navigation code.

Passing Letter With Safe Args

Safe Args is a Gradle plugin that generates objects and builder classes for type-safe access to arguments specified for destinations and actions. In other words, it forces you to pass correct and sufficient arguments into the fragment when you navigate to it.

To use Safe Args, open build.gradle under app. Add the following line of code the top of the file:

apply plugin: "androidx.navigation.safeargs.kotlin"

Run Gradle sync in Android Studio again.

Now, you’ll make PresentationFragment require a serialized Letter string as an argument. PresentationFragment converts the serialized Letter string into an object and assigns it to the ViewPager.

Open nav_graph.xml, on Design view, then click the presentationFragment in the graph on the left. On the Attributes panel, you’ll find the Arguments section. Click the + on the right hand side.

Attributes Panel

Name the argument letter and set its type as String. Click Add. That’s it.

Add Letter Argument

Getting Letter From Safe Args

Open PresentationFragment.kt. Assign lettersViewModel to the navigation graph ViewModel:

private val lettersViewModel: LettersViewModel by navGraphViewModels(R.id.nav_graph)

Then, add the following line of code right below the line above to get the argument’s object:

private val args: PresentationFragmentArgs by navArgs()
Note: PresentationFragmentArgs is a generated class. If the compiler gives you an error saying that it can’t find the class, make sure to build your project in Android Studio first.

Inside onViewCreated, under super.onViewCreated(view, savedInstanceState), add the following code:

val letter = Gson().fromJson(
  args.letter.urlDecode(),  //1
  Letter::class.java
)
lettersViewModel.saveLetterToInbox(letter)  //2

viewPager.adapter = context?.let {
  LetterPagerAdapter(
    it, letter  //3
  )
}

Here’s a breakdown of this code:

  1. The args object contains the letter argument. It’s type is String. You can go to its declaration to see the code of the generated class. urlDecode() is a String extension that decodes the URL-encoded string because the serialized Letter is used as a part of URL.
  2. Save the opened letter to inbox. This mimics the behavior of receiving the letters in the inbox so you can reopen them.
  3. Pass the Letter object to the ViewPager. The ViewPager presents the letter in three sliding pages.

You’ve setup the PresentationFragment. Now you can PUSH a new letter and open it from a push notification!

Open From Push Notification

Give yourself a pat on the back! :]