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.
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
Android Jetpack Architecture Components: Getting Started
35 mins
- Getting Started
- Adding Dependencies for Architecture Components
- Creating ROOM for Your Contacts
- Creating Entities
- Creating a Data Access Object (DAO)
- Creating the Database
- Pre-populating a Room Database
- Live Updates With LiveData
- Introducing ViewModel
- Mastering ViewModel and LiveData
- Implementing Search
- Mapping With LiveData Transformations
- ViewModels Everywhere
- Architecture Layers
- Exploring Navigation Components
- Preparing for Navigation
- Navigating to the Next Fragment
- Navigation With Additional Data
- Where to Go From Here?
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 New ▸ Android 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.
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:
- You are declaring the
navigationController
instance for MainActivity. - The NavController is actually a part of a NavigationHostFragment attached to this Activity. This section initializes the
navigationController
instance usingfindNavController()
. Then, the NavigationUI helper class ties thenavigationController
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. - 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!
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:
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.
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:
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:
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:
Build and run. It’ll show iMet as 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!
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.