Using Android Jetpack Lifecycle-Aware Components

Kayvan Kaseb
Software Development
6 min readMay 14, 2020
Photo is provided by Unsplash

As a matter of fact, one of the main problems in Android development is facing with lifecycle management issues. In other words, failing to handle application lifecycles appropriately can cause some problematic issues such as memory leaks and some crashes. Lifecycle-aware components as a part of Android Architecture Components accomplish tasks in response to a change in the lifecycle status of another component, such as activities and fragments. As a result, these components help you create better-organized, and often lighter-weight code, that is easier to maintain and test. This essay aims to consider Android Jetpack Lifecycle-aware components as an advanced approach for managing lifecycles in Android development.

Overview and Introduction

Android Architecture Components is a new collection of libraries by Google, which aims to help us design Android applications that are robust, testable, and maintainable. In other words, this component helps us handle data across lifecycle events and configuration changes, and also create a proper architecture for our classes for maintenance and test.

Fundamentally, most Android components have a lifecycle that are associated with them. You used to be responsible for handling your app’s lifecycle, which was not always easy task particularly for multiple asynchronous calls in a simultaneous way. Failing to handle application lifecycles appropriately can cause some problematic issues such as memory leaks and some crashes. Although you managed the lifecycle correctly, implementing all of that lifecycle-dependent code in your lifecycle methods such as onStart() and onStop() methods was complicated. In short, this approach makes methods difficult to read, maintain, and test.

The picture is provided by Google document

So, the Lifecycle library provides an advanced approach to lifecycle management by supporting all the classes and interfaces needed to implement lifecycle-aware components, which adjust their behavior automatically, and even accomplish various actions in response to lifecycle events. In addition, there is no guarantee that the component starts before the activity or fragment is stopped. For instance, if we have to perform a long-running task like some configuration check in onStart(). This can lead to a race condition where the onStop() method finishes before the onStart(). This means keeping the component alive longer than it is needed. For example, assume we have an activity that represents the device location on the screen as follow:

class MyActivity : AppCompatActivity() {
private lateinit var myLocationListener: MyLocationListener
override fun onCreate(...) {
myLocationListener = MyLocationListener(this) { location ->
// update UI
}
}
public override fun onStart() {
super.onStart()
Util.checkUserStatus { result ->
//If this callback is invoked after activity is stopped, what should we do?
if (result) {
myLocationListener.start()
}
}
}
public override fun onStop() {
super.onStop()
myLocationListener.stop()
}
}

Lifecycle-aware components help you manage your activity and fragment lifecycles. Survive configuration changes, avoid memory leaks and easily load data into your UI.

In fact, since this process is automated, Lifecycle helps you avoid some problems caused by lifecycle mismanagement. As a result, your code would be be much more organized. and it would be easier to read, maintain, and test.

What is the definition of lifecycle awareness?

An object is mentioned to be lifecycle-aware if it is able to detect and respond to changes in the lifecycle state of other objects within an app. Some Android components like LiveData are already lifecycle-aware. In addition, it is possible to configure any class to be lifecycle-aware by implementing the LifecycleObserver interface within the class.

Lifecycle

Initially, Lifecycle is an abstract class that has an Android Lifecycle attached to it. Objects can observe this state and act appropriately.

Lifecycle is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state.

To keep a track of this state, there are two main concepts that are represented as Enums: Events and State.

States and events in Lifecycle, the picture is provided by Google Document

As a matter of fact, in above diagram, states are nodes of a graph, and events are the edges between these nodes. Basically, a class can monitor the component’s lifecycle status by using annotations in its methods. For instance:

class MyObserver : LifecycleObserver {

@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun connectListener() {
//...
}

@OnLifecycleEvent(Lifecycle.Event.ON_PAUSE)
fun disconnectListener() {
//...
}
}

In fact, the @OnLifecycleEvent annotation can react to the following lifecycle events:

  • ON_CREATE
  • ON_DESTROY
  • ON_PAUSE
  • ON_RESUME
  • ON_START
  • ON_STOP
  • ON_ANY

Note: The method assigned to the ON_ANY event will be called for all lifecycle events.

After that, you can be able to add an observer by calling the addObserver() method of the Lifecycle class and passing an instance of your observer as follow:

myLifecycleOwner.getLifecycle().addObserver(MyObserver())

You should add this line of code in your onCreate() method of your activity in order to associate the LifecycleOwner with the LifecycleObserver by using getLifecycle().addObserver().

LifecycleOwner

An interface that is implemented by objects with a Lifecycle. Fragments and Activities already implement the LifecycleOwner interface in Support Library 26.1.0+, and are LifecycleOwners by default. Custom classes may also be configured as lifecycle owners by using the LifecycleRegistry class and implementing the LifecycleObserver interface.

Besides, when the status of a lifecycle owner changes, the assigned Lifecycle object will be updated with the new state. At any time, a lifecycle owner will be in one of the following five states:

  • Lifecycle.State.INITIALIZED
  • Lifecycle.State.CREATED
  • Lifecycle.State.STARTED
  • Lifecycle.State.RESUMED
  • Lifecycle.State.DESTROYED

Thus, the isAtLeast() method of the current state object may also be used when the owner state needs to be at a certain lifecycle stage:

if(getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) { //...
}

Eventually, if you are trying to handle the lifecycle of a whole application process, you should use ProcessLifcyceOwner.

Some use cases for lifecycle-aware components

As a matter of fact, Lifecycle-aware components can make it much easier for you to manage lifecycles in a variety of cases. For instance:

  1. Stopping and starting video buffering
  2. Starting and stopping network connectivity.
  3. Pausing and resuming animated drawables.

LiveData

Additionally, the Lifecycle library supports the foundation for additional Android Architecture Components, including LiveData. LiveData is an observable wrapper that can hold any data, including Lists. Once a LiveData has a value, it will notify its assigned Observers whenever that value changes.

LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services. This awareness ensures LiveData only updates app component observers that are in an active lifecycle state.

However, in contrast to a regular Observable, LiveData is lifecycle-aware. Therefore, it only updates Observers that are in an “active” state such as STARTED or RESUMED. If the LifecycleOwner reaches a Lifecycle.State.DESTROYED state, then the LiveData will eliminate the Observer automatically. This lifecycle-awareness helps you avoid the crashes that can occur if you try to update a stopped Activity or Fragment. Whenever a component enters the STARTED state, it automatically receives the most recent value from the LiveData object it is observing. If an Activity or Fragment is resumed, or recreated as part of a configuration change process, it will receive the latest data.

Some best practices for lifecycle-aware components by Google

  1. Keep your UI controllers (activities and fragments) as lean as possible by using LiveData and ViewModel

2. Put your data logic in your ViewModel class. In fact, ViewModel should use as a connector between your UI controller and the rest of your app.

3. Use Data Binding to maintain a clean connection between your views and the UI controller.

4. Avoid referencing a View or Activity context in your ViewModel.

In conclusion

This essay considered Android Jetpack Lifecycle-aware components as some advanced classes for handling lifecycles in Android apps based on Google resources. In fact, these libraries could be helpful in some cases such as stopping and starting video buffering, starting and stopping network connectivity, and pausing and resuming animated drawables. In addition, you can be able to use LiveData as an lifecycle-aware approach in your Android apps.

--

--

Kayvan Kaseb
Software Development

Senior Android Developer, Technical Writer, Researcher, Artist, Founder of PURE SOFTWARE YAZILIM LİMİTED ŞİRKETİ https://www.linkedin.com/in/kayvan-kaseb