Android Jetpack Architecture Components: Getting Started

In this tutorial, you will learn how to create a contacts app using Architecture Components from Android Jetpack like Room, LiveData and ViewModel. By Zahidur Rahman Faisal.

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

Preparing for Navigation

You’ve already added the necessary dependencies for using Navigation Components, so you’ll now focus on the implementation.

Right-click on the res directory and select NewAndroid Resource File. In the New Resource File dialog, input navigation_graph as File name and select Navigation in the Resource type drop-down list. Then click OK.

New navigation graph

Now, you need to modify the activity_main.xml layout to define it as the single entry point in your navigation graph. To do that, update activity_main.xml to the following:

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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=".ui.MainActivity">

  <fragment
    android:id="@+id/navigationHostFragment"
    android:name="androidx.navigation.fragment.NavHostFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:defaultNavHost="true"
    app:navGraph="@navigation/navigation_graph" />

</android.support.constraint.ConstraintLayout>

Here, you are attaching a NavHostFragment inside MainActivity as the default navigation host (or default entry point) for all other Fragments. The NavHostFragment is a part of the Navigation Architecture Components library. app:navGraph="@navigation/navigation_graph" is referencing the navigation_graph.xml file you created in order to know about possible destinations from NavHostFragment.

You’ll need to update MainActivity so that it handles Back or Up navigation, utilizing Navigation Architecture Components, and so you won’t need to bother about managing the Fragment Back-Stack later. Replace everything inside MainActivity to be as follows:

package com.raywenderlich.android.imet.ui

import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import androidx.navigation.NavController
import androidx.navigation.findNavController
import androidx.navigation.ui.NavigationUI
import com.raywenderlich.android.imet.R

class MainActivity : AppCompatActivity() {

  //1
  private lateinit var navigationController: NavController

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    //2
    navigationController = findNavController(R.id.navigationHostFragment)
    NavigationUI.setupActionBarWithNavController(this, navigationController)
  }

  //3
  override fun onSupportNavigateUp() = navigationController.navigateUp()
}

Take some time to understand each segment of the above snippet as numbered:

  1. You are declaring the navigationController instance for MainActivity.
  2. The NavController is actually a part of a NavigationHostFragment attached to this Activity. This section initializes the navigationController instance using findNavController(). Then, the NavigationUI helper class ties the navigationController with the ActionBar in this Activity. This is necessary to allow the ActionBar to show a Back button whenever a child fragment is attached to this Activity.
  3. This override lets the navigationController handle the Fragment Back-Stack internally when a user performs a Back or Up action.

Now, open navigation_graph.xml to set PeoplesListFragment as your initial destination. Click on the New Destination button on top. Then, select the fragment_people_list layout from the dropdown — easy!

Add to nav graph

So, now, PeoplesListFragment will be loaded in the NavigationHostFragment by default when you launch the app.

Navigating to the Next Fragment

Next we’ll add the ability to navigate to the AddPeopleFragment. Click on the New Destination button on top and select the fragment_add_people layout from the dropdown menu. This will add another destination, AddPeopleFragment, in the Navigation Graph. Now, select PeoplesListFragment again — you’ll see a small circle appear. Drag the circle to the AddPeopleFragment. A connector arrow will appear in between those destinations:

Adding an action

Now, open the PeoplesListFragment class and replace the code inside addFab.setOnClickListener with the following code:

view.findNavController().navigate(
    R.id.action_peoplesListFragment_to_addPeopleFragment)

Here, you’re using the NavController from the attached view to perform the navigation instead of using a new intent.

Note: R.id.action_peoplesListFragment_to_addPeopleFragment is a automatically generated unique identifier by Android Studio as a result of connecting PeoplesListFragment and AddPeopleFragment in the Navigation Graph.

Now, open the AddPeopleFragment class and replace this line inside savePeopleInfo(),

activity?.finish()

with this:

Navigation.findNavController(view!!).navigateUp()

The above line navigates users back using NavController instead of finishing the Activity when new People are added.

Build and run. Navigate to AddPeopleFragment and try adding new people to check that the Navigation Components are working properly.

If everything works as expected, AddPeopleActivity is not necessary anymore. You can delete the AddPeopleActivity class and activity_add_people.xml from the project. Remember to remove the following lines from AndroidManifest.xml:

<activity
  android:name=".ui.add.AddPeopleActivity"
  android:label="@string/add_people"
  android:parentActivityName=".ui.MainActivity" />

Also, remove the reference to AddPeopleActivity inside PeopleListFragment, if it’s still there.

You’re just one step away from completing the Navigation challenge! Next, you’ll eliminate PeopleDetailsActivity to complete it…

Navigation With Additional Data

Open navigation_graph.xml again and add the PeopleDetailsFragment by clicking the New Destination button. Then, connect PeoplesListFragment to PeopleDetailsFragment just like the previous step. Your navigation_graph.xml will now look like this:

Full navigation graph

Now, open PeoplesListFragment and replace the code inside onItemClick() with the following:

val peopleBundle = Bundle().apply {
  putInt(getString(R.string.people_id), people.id)
}
view?.findNavController()
    ?.navigate(R.id.action_peoplesListFragment_to_peopleDetailsFragment, peopleBundle)

Again, this function uses the NavController from the attached view to perform the navigation instead of creating a new intent, but, this time, with an additional parameter, peopleBundle, which carries the id of the selected People object to the destination PeopleDetailsFragment.

Next, open the PeopleDetailsFragment class and replace this line inside onViewCreated(),

val peopleId = activity?.intent?.getIntExtra(getString(R.string.people_id), 0)

with this one:

val peopleId = arguments?.getInt(getString(R.string.people_id))

Here, the arguments variable of this Fragment returns the bundle passed with NavController during navigation.

Now, build and run again. Select an item from the people list to navigate to the PeopleDetailsFragment. Check if the Navigation Components are carrying your data properly and displaying the correct item in PeopleDetailsFragment.

You can now remove the PeopleDetailsActivity class along with the activity_peoples_details.xml layout! Also, remove the following lines from AndroidManifest.xml:

<activity
  android:name=".ui.details.PeopleDetailsActivity"
  android:label="@string/people_details"
  android:parentActivityName=".ui.MainActivity" />

Remember to remove the import of PeopleDetailsActivity at the top of your PeopleListFragment, if it’s still there.

Finally, all seems complete. Build and run. You should see that everything works fine with your Single-Activity Architecture:

App with Single-Activity Architecture

But wait — did you notice the title on top of the screen? Who changed that?

Well, the title is auto-generated for all your Fragments when you imported them into navigation_graph.xml. You can change the title easily from your IDE.

Open navigation_graph.xml again and select PeoplesListFragment. Change the Label from the Attributes panel to iMet like below:

Changing a Label

Build and run. It’ll show iMet as title:

iMet title

Now, select AddPeopleFragment in the navigation graph and change the title to Add People. Similarly, change the title of PeopleDetailsFragment to People Details.

Build and run once again. You should see the correct title on each screen.

You completed the final challenge: Implementing Proper Navigation!

All Complete!

Congratulations!

In this quest, you’ve learned how to:

  • Add a local database with Room.
  • Use advanced features of LiveData.
  • Deal with data using ViewModel.
  • Use Navigation Architecture Components for easy navigation.
  • Implement a Single-Activity Architecture.