Android Architecture Components: Lifecycle and LiveModel

Android Architecture Components: Lifecycle and LiveModel

In the last part of this series, Introduction to Android Architecture Components, we talked about the new Android Architecture and why it was developed. Basically, the new architecture addresses some known Android issues by offering a bundle of components tailor-made for the system. These are the building blocks of the architecture. We've already had a quick look at these components, so now it is time to start to deep dive into them. 

In this tutorial, we'll take a close look at the Lifecycle and the LiveModel components. While we're exploring these, we're also going to check out some code snippets from a sample application. Since we're talking about Android's new paradigms, the snippets are all made with the awesome Kotlin.

If you don't know Kotlin yet, please don't be afraid to follow along; the implementation is extremely close to Java, and I'm confident that you'll be able to understand it. If you want to learn more about Kotlin, Jessica Thornsby wrote an excellent series here on Tuts+ about Coding Android Apps in Kotlin. You should take a look!

1. The Sample Project

We provided a small application demonstrating the concepts that we're talking about in this tutorial. The app's name is MyWeatherApp, and it allows the user to fetch the day's weather using a city's name or the user's current location. The app's logic is quite simple, but you could improve on it to create your own application.

Sample Application

As you can see in the diagram below, the architecture conforms to the one proposed by Android, and we used the new Architecture Components package as much as possible, keeping things simple enough for a basic analysis. As a bonus, we're using Dagger 2 as a Dependency Injection library. However, we won't dig into much detail about its implementation, since it would escape the tutorial's scope.

The WeatherApplication

How Does the App Work?

The application is as simple as possible. It has only one Activity, where the user can get the weather by searching a city's name or using the device's current location. The MainActivity calls the MainModel to get an observable LiveData and reacts to it. The MainModel fetches weather data from the MainRepository, and consolidates all data as LiveData. The MainRepository gets its data from multiple sources.

Running the Sample App

Download or clone the repository from our GitHub repo and build with Gradle or open it in your IDE. You must also create an OpenWeatherMap account and get a new application ID. Add the application ID on a string resource called openWeather.

2. Setting Up a Project

Since the Architecture Components are still in alpha, you have to include the Google repository, which contains some experimental libraries, in the project's build.gradle.

In the module build.gradle, add the following to the dependencies section to add support for Lifecycles, LiveData, and ViewModel:

  • compile "android.arch.lifecycle:runtime:1.0.0-alpha5"
  • compile "android.arch.lifecycle:extensions:1.0.0-alpha5"
  • annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha5"

If you're using Kotlin, you must also add or replace the annotationProcessor with kapt, which handles annotation on Kotlin.

To enable kapt, add the following in the module's build.gradle root.

3. The Lifecycle Component

Every Android developer is familiar with the lifecycle concept. The system drives the lifecycle of Applications, Activities, Fragments, and so on, without the control of the developer. This concept is one of Android's paradigms and, until recently, it wasn't that easy to work with, since it wasn't possible to directly check for the current lifecycle status of a component. What we could do was to react to certain methods, like onCreate and onDestroy, triggered by lifecycle events.

Activity Lifecyle

This has all changed since the announcement of the Architecture Components package, which introduced a component called Lifecycle. Now, some Android objects have a Lifecycle attached to them, and this changes lots of things for the developers. It is possible to consult a Lifecycle state at any given time, and it is also possible to react to Lifecycle events using annotations. In fact, the backbone of the new Android Architecture Components is the Lifecycle component.

All elements of the package android.arch.lifecycle are important to the lifecycle concept, but two of them deserve more attention: LifecycleOwner and LifecycleObserver. They create the possibility of working with Lifecycle, observing as well as reacting to events that occur on Activities, Fragments, Services and so on.

The LifecycleOwner

The LifecycleOwner is a single method interface for classes that contain a Lifecycle. It abstracts the possession of a Lifecycle, allowing you to write components that can work with it. By the new standards, Activities and Fragments are LifecycleOwners. However, until the final version of the Architecture Components is launched, you must use some special classes: ActivityLifecycle, FragmentLifecycle, and LifecycleService.

There's no significant change in the implementation of these classes when compared to the standard Activities and Fragments. Once a class extends any of them, it will have a Lifecycle attached, which can be fetched at any time with the method getLifecycle(). Another interesting possibility is that we can check the current lifecycle state with getCurrentState, which returns a Lifecycle.State. 

There are five different Lifecycle states:

  • INITIALIZED: for an object that has been called, but which isn't "active" yet. It is the equivalent to a state before the Activity.onCreate method.
  • CREATED: for objects that were just created. It is called after the onCreate method and also called just before the onStop method.
  • STARTED: called after the onStart and just before the onPause method.
  • RESUMED: The active state or the resumed state for a LifecycleOwner. Called after the onResume method.
  • DESTROYED: for a destroyed LifecycleOwner object. This Lifecycle won't dispatch more events. This event is reached right before the onDestroy method.
LifecycleOwner Events

The LifecycleObserver

One of the most interesting properties of the Lifecycle is that it can easily be observed.  LifecycleObserver classes can observe LifecycleOwner components, like Activities and Fragments. It receives LifecycleOwner.Events, and can react to them through the annotation @OnLifeCycleEvent( Lifecycle.Event ).

The methods annotated with @OnLifecycleEvent don't need arguments, but if used, the first argument must be the LifecycleOwner. When the annotation uses Lifecycle.Event.ON_ANY, the method should expect two arguments: LifecycleOwner and Lifecycle.Event.

To activate the @OnLifecycleEvent annotation, the LifecycleObserver must be observing a Lifecycle, otherwise it won't receive the event. To make this work, call Lifecycle.addObserver(LifecycleOwner) and the LifecycleOwner will subsequently be able to react to Lifecycle.Event. It is also possible to call Lifecycle.removeObsever(LifecycleObserver) to remove an observer.

There are various interesting use-cases for LifecycleObserver. For example, it could be used to create a Presenter layer from the Model View Presenter architecture pattern. It could also be used to create listeners that can stop listening when the Lifecycle is disabled.

4. The LiveModel Component

Designed to work together with the UI layer, the ViewModel component closes a gap that has existed in Android since the beginning: providing a way to elegantly manage and store data objects related to the view. The component maintains data integrity between configuration changes, can be shared between Activity and Fragments, and is an excellent tool to completely avoid memory leaks.

The ViewModel is always created in close relation to a specific scope, either an Activity or Fragment. The scope is retained as long as the Activity or Fragment is alive. In practical terms, the ViewModel reconnects with the view after configuration changes, maintaining itself until the main view is destroyed. According to the official documentation:

The purpose of the ViewModel is to acquire and keep the information that is necessary for an Activity or a Fragment.

On top of all that, the ViewModel facilitates the separation of concerns in the Android development process. By moving all the data-related operations to this component and letting it handle the logic, the application testability and maintainability is greatly increased. With ViewModel, it's possible to easily adopt the Android Architecture proposed at the 2017 Google I/O. You can even use it to adopt more sophisticated architecture patterns, like MVP or MVVM.

Implementing a ViewModel

There are two ways to implement a ViewModel. The standard one is to extend the class, providing a no-argument constructor. This is the easiest way, but it doesn't work well with Dependency Injection.

To get a ViewModel constructed with this technique from an Activity or Fragment, simply call ViewModelProviders.of(FragmentActivity).get(Class<T>). The last argument must contain the ViewModel class. The same ViewModel instance will be fetched by the view and will contain all the data for that view.

Notice that, since the ViewModel is taken from ViewModelProviders.of method, its constructor cannot receive arguments. As a workaround, you can implement a ViewModelProvider.Factory. Actually, this is the same technique we use to inject ViewModel.

Injecting a ViewModel

When using DI, things get a little trickier. You'll need to implement a ViewModelProvider.Factory. The following steps can be used to inject a ViewModel using Dagger. The ViewModelFactory is a utility class that provides a ViewModel for a scope.

Dagger also needs a @MapKey defined for ViewModel and a binder for each model and for the factory in the module.

After that, follow the standard Dagger procedures and you'll be able to create a ViewModel capable of injecting arguments on its constructor. To create a new instance, get the ViewModelFactory and take the desired ViewModel from it.

In our sample project, you can take a close look at DI using Dagger. I've also provided you with a folder of examples in the tutorial GitHub repo with snippets showing how to configure ViewModels on the Dagger system using Kotlin.

Conclusion

So far, our journey through the new Android Architecture Components has been very productive. However, we still have some ground to cover. In the next tutorial, we’ll talk about the awesome LiveData component, investigating its basic and advanced features, and applying these concepts to our sample application.

See you soon! And in the meantime, check out some of our other posts on Android app development!

Source: Tuts Plus

About the Author