Lifecycle-Aware Components Using Android Jetpack

Learn about lifecycle-aware components including what they are, how they work, how to implement your own components and how to test them. By Rodrigo Guerrero.

Leave a rating/review
Download materials
Save for later
Share

Android Jetpack is a collection of libraries that help developers improve their code, reduce boilerplate code and make their app work consistently across different Android versions. Jetpack’s Android Architecture Components provide tools to help implement lifecycle-aware components that react to lifecycle changes in activities or fragments.

In this tutorial, you’ll create a lifecycle-aware component in an app named AwarenessFood. This component will improve how the app handles network connection changes. You’ll also create a lifecycle owner that will communicate the network state to the activity.

The app shows a random recipe to the user and has two menu options: one to get a new random recipe and the other to show some food-related trivia. When the device is offline, the main screen shows a snackbar with a message and a retry option.

Over the course of this tutorial, you’ll learn about:

  • Lifecycles in Android
  • Lifecycle-aware components
  • Lifecycle observers
  • Events and states
  • Lifecycle owners
  • How to test your lifecycle-aware components
  • LiveData
Note: This tutorial assumes you know the basics of Android development. If you’re new to Android development, check out this Android Tutorial for Beginners.

Getting Started

Download the materials using the Download Materials button at the top or bottom of this tutorial. Open Android Studio 4.2.1 or later and import the starter project.

Below is a summary of what each package does:

  • analytics: Contains classes for tracking app events.
  • data: Contains model classes.
  • di: You’ll find classes for providing dependency injection here.
  • monitor: Contains a single class for observing network connectivity.
  • network: Here, you’ll find classes for accessing external APIs.
  • repositories: Has classes for managing persistence.
  • viewmodels: Contains business logic classes.
  • views: Holds a custom View.

Registering for the spoonacular API

AwarenessFood uses the spoonacular API to fetch recipes. You’ll need to register for this API to be able to run the app successfully.

Go to the spoonacular website and create a new account. Once you confirm your account, log in and go to your profile to find your API key. Copy it, open RecipesModule.kt inside the di package and replace the value in the following line:

private const val API_KEY = "YOUR_API_KEY_HERE"

Build and run. You’ll see a screen with a random recipe, similar to the one shown below. Bonus points if you get the same recipe as in the image. :]

AwarenessFood app running

To get another random recipe, press the Reload button in the action bar. If you try to get a new recipe and your device goes offline, you’ll see a snackbar with the error message and retry button, as shown below:

Network error showing in a snackbar.

To go to the food trivia screen, press the Food Trivia option in the More menu. You’ll implement this functionality later in the tutorial. Right now, you’ll only see a button to get the food trivia, as shown below:

Food trivia section in the app

This completes the setup you need to run the app. Now, you’re ready to learn about lifecycle-aware components.

Lifecycles in Android

An important basic concept you need to understand as an Android developer is how the lifecycle of activities and fragments work. The lifecycle is a series of callbacks executed in a certain order when the status of the activity or fragment changes.

The lifecycle is important because certain actions need to take place when the activity or fragment is in a specific state. For example, setting the activity layout needs to take place in its onCreate().

In a fragment, you need to create the view and set its layout in onCreateView(). Another example is enabling the current location reading in onStart().

For the destruction process, the location reading should stop in onStop(), which is also where you need to unregister other components. It’s important to know that not all the callbacks get executed every time. For example, the operating system may or may not execute onDestroy().

The following diagram shows the complete lifecycle for activities:

Activity Lifecycle

If you want to know more about activity’s lifecycle, go to our Introduction to Android Activities With Kotlin tutorial.

This diagram shows the lifecycle for fragments:

Fragment Lifecycle

If you want to know more about a fragment’s lifecycle, read Android Fragments Tutorial: An Introduction With Kotlin.

Reacting to Lifecycle Changes

Most apps have multiple components that need to react to the lifecycle of an activity or fragment. You need to initialize or register these components in onStart() and unregister or perform some cleanup in onStop(). In some cases, you need to do some other actions during another lifecycle callback.

Following this pattern, your code can become messy and error-prone. The code within onStart() and onStop() will expand indefinitely. Meanwhile, it’s easy to forget to unregister some of your components or to call the component’s methods in the wrong lifecycle callback, causing bugs, memory leaks and crashes.

You can see some of these problems in the app right now. Open NetworkMonitor.kt in the starter project. This class is in charge of listening to the state of the network connection and notifying the activity if the state of the connection changes.

Note: For more information about monitoring the network connection, visit the Read Network State documentation.

The NetworkMonitor instance needs to be available from the initialization of the activity. Open MainActivity.kt, which contains the code to initialize it in the onCreate() by calling networkMonitor.init().

NetworkMonitor then registers the network callbacks in onStart() by calling networkMonitor.registerNetworkCallback(). Finally, it unregisters these callbacks in onStop() by calling networkMonitor.unregisterNetworkCallback().

Initializing the component, registering the callbacks and unregistering them again add a lot of boilerplate code to the activity. Besides, you only need to add onStart() and onStop() to call the NetworkMonitor methods.

In MainActivity, there’s only one component that needs to react to lifecycle changes. However, in a bigger and more complex app, several components need to do the same, it can become a complete mess.

Using Lifecycle-Aware Components

NetworkMonitor performs different actions that depend on the state of the lifecycle of the activity where it lives. In other words, NetworkMonitor needs to be a lifecycle-aware component and react to changes in the lifecycle of its parent — in this case, MainActivity.

Jetpack provides classes and interfaces to help create lifecycle-aware components. By using them, you can improve the way NetworkMonitor performs its actions. These actions will execute automatically according to the current lifecycle state of its parent activity.

A lifecycle owner is a component that has a lifecycle, like an activity or a fragment. The lifecycle owner needs to know all the components that need to listen for its lifecycle changes. Using the observer pattern is the best approach to achieve this.