How to Work With Android Architecture Components (Example Project)

Android Architecture Components (AAC) is a new collection of libraries that contains lifecycle-aware components. AAC were introduced at Google I/O 2017 and were designed by the Android framework team to make it easier to create Android apps?. There are four components of AAC:

  • Room

  • ViewData

  • LiveData

  • Lifecycle

In this article, I’ll tell you how to deal with those shiny new architecture components and share my experience developing a project with them.


AAC has a bunch of benefits. They’re great for:

  • Solving problems with configuration changes

  • Supporting data persistence

  • Boilerplate code

  • Preventing memory leaks

  • Simplifying asynchronous data loading into your UI, and more.

I can’t say that AAC brings a totally new approach for solving these issues, but finally we have a formal, single, and official direction.

AAC provides some abstractions to deal with the Android lifecycle:

  • LifecycleOwner

  • LiveData

  • ViewModel



LifecycleOwner is a single method interface that provides an instance of a Lifecycle object. The library already includes a LifecycleActivity that inherits from FragmentActivity and implements LifecycleOwner. It also contains a LifecycleFragment that inherits from Fragment in the support library.


LifecycleRegistry is a default implementation of Lifecycle that you can use for a custom LifecycleOwner.


Note that you have to hold a strong reference to the instance of LifecycleRegistry. Otherwise, the garbage collector will collect it and the LifecycleObserver of LiveData won’t see the active observers from LifecycleOwner, and your views won’t be updated.


You can take a look at the source code for LifecycleRegistry to better understand lifecycle management.

How does LiveData work?

LiveData is a holder for some data and an implementation of the Observable pattern. It lets you detect data changes inside an instance of LiveData similarly to RxJava Observable.


The main benefit of LiveData is that your UI components, including TextView and RecycleView, observe LiveData which, in turn, observes the lifecycle of an Activity or Fragment using a LifecycleObserver.


To change the data inside LiveData, you can use the setValue method from a main thread or the postValue method from a background thread. If you call postValue multiple times before the main thread has executed a posted task, only the last value will be dispatched.


Since LiveData is an abstract class, the library is simple to implement:


MediatorLiveData is a subclass of MutableLiveData. You can use it to detect changes in other instances of LiveData.


An isLoadingLiveData object observes a resultLiveData object and correctly detects active/inactive states and informs the source object about state changes.

How does ViewModel work?

ViewModel is a view data ownership model that assumes the following responsibilities:

  • Automatic retention during configuration changes

  • Management of async calls

  • Holding data for the UI

Thanks to LifecycleOwner, ViewModel has the simple view of the lifecycle of an Activity or a Fragment: initialization and cleaning.


The instance of ViewModel isn’t destroyed during configuration changes. The new Activity gets the existing ViewModel object and immediately receives latest data with the use of LiveData.


This persistence makes ViewModel a really powerful and convenient tool for dealing with lifecycle changes. Using LiveData as a type of ViewModel field is the best practice for creating a screen with a mutable state of view data as well as asyViewModelProviders, refers to the ViewModelStore to return an existing instance if one behavior. Such a system immediately reacts to changes.

You can use the ViewModelProviders class to get the instance of ViewModel:


ViewModelProviders, refers to the ViewModelStore to return an existing instance if one exists.


The ViewModelProviders library also contains the AndroidViewModel class that takes an Application as an argument in the constructor.


The combination of LiveData, LifecycleOwner, and ViewModel solves the main challenges faced by Android developers, such as boilerplate code and modularity. I decided to create a sample project to explore this concept. The app I created just gets a list of repositories from Github and shows one using RecyclerView.


As you can see, my app handles configuration changes without any problems due to the combination of architecture components. The Activity looks simple:


You may notice that your activity assumes the minimum number of responsibilities. ReposViewModel holds state and view data in the following way:


The state of the screen can be described as follows:

state: { isLoading: true, repositories: [], exception: null }

Transformations is a util class that has two methods: map and switchMap. Both take two arguments – source LiveData plus a function – and create a new LiveData instance. This LiveData instance then reacts to changes in the source LiveData and applies the function it has been passed.

I also created a custom ReposLiveData:


ReposLiveData takes an instance of Repository and the name of an organization, loads data, and sets them up to the LiveData instance. An onInactive() method is called when the number of active observers changes from 1 to 0, giving the opportunity to dispose of a Single in RxJava. ReposLiveData is one of the ways to convert a live collection of RxJava to LiveData.

You can use the LiveDataReactiveStreams class to convert Flowable to LiveData, and vice versa. To add the LiveDataReactiveStreams class to your project, add the following dependency:

​compile 'android.arch.lifecycle:reactivestreams:' + rootProject.archLifecycleVersion

LiveDataReactiveStreams is a util class that contains two methods:

​public static <T> LiveData<T> fromPublisher(final Publisher<T> publisher)


public static <T> Publisher<T> toPublisher(
       final LifecycleOwner lifecycle, final LiveData<T> liveData) {

Repository pattern

Let’s move to implementation of the Repository pattern and explore the Room component of AAC.


My sample project invokes a request to the Github API and saves the result to local storage. This helps me get existing data from a database without the need to use expensive requests to the GitHub Rest API. This is also why the app can work without an internet connection.

I chose the new Room Persistence Library for my local datastore. Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite. Room has the following benefits:

  • It’s an ORM (Object-Relational Mapping) library, so you don’t have to write boilerplate code to convert Cursor to POJO (Plain Old Java Object) or to SQL queries.

  • Compile-time verification of raw SQL queries

  • Ability to use the power of relational databases

Room also has some drawbacks:

  • You have to write raw SQL

  • It’s slower than NoSQL

There are three major components in Room:

#1 Database


The annotation defines a list of entities and the schema version. AppDatabase’s content defines the list of data access objects (DAOs) in the database.

To create a database asynchronously, I used singleton design pattern and Builder from the Room class.


You can use isDatabaseCreated LiveData to detect when the database has been created.

Finally, we can invoke the createDb method from the App class.


#2 Entity

An Entity is a class that holds a database row.


There are a lot of annotations that can be helpful for you, including:

@ColumnInfo(name = "first_name"), @Insert, @Delete, @Ignore, @ForeignKey

Note that an Entity doesn’t require an empty constructor (unlike RealmObject), and you can use it as a data class. However, I received this error when I added more than two constructors with args:

/entities/ error: Room cannot pick a constructor since multiple constructors are suitable. Try to annotate unwanted constructors with @Ignore.

#3 DAO

A DAO represents a class or interface as a Data Access Object (DAO). DAOs are the main component of Room. They allow you to define the methods that access the database. Classes annotated with @Database must contain an abstract method that has 0 arguments and returns a class annotated with @Dao. When generating code at compile time, Room creates an implementation of this class for you.


Traditionally, I’ve used Retrofit to deal with HTTP. But in this sample, I decided to try the Fuel library.

Here are some of the main features of Fuel:

  • Support for basic HTTP GET/POST/PUT/DELETE/HEAD in a fluent style interface

  • Support for both asynchronous and blocking requests

  • File download

  • File upload (multipart/form-data)

  • Cancellation of in-flight requests

  • Request timeout

  • Manager configuration using FuelManager

  • Debug log/cUrl log

  • Support for response deserialization into plain old object (both in Kotlin & Java)

  • Automatic invocation of handlers on Android Main Thread when using Android Module

  • Special test mode for easier testing

  • RxJava 2.x support out of the box

Retrofit requires a lot of boilerplate code to create a Service and to add OkHttp. A Get request with Fuel looks like this:


This is all that you need to perform the request. Using FuelManager, you can set up interceptors or SSL certificates, so it’s a really convenient and useful library.

Finally, our repository looks like this:


Together, this set of libraries provides the basic components needed to create modular, testable, and robust Android apps. But that doesn’t mean that these libraries only work as a complete package. If you don’t want (or need) all of them, you can just pick the ones that you do need.

Now you know how to combine AAC with the Repository pattern and how to create a robust Android app. Both Java and Kotlin work with AAC. The source code is available on Github.

3.7/ 5.0
Article rating
Remember those Facebook reactions? Well, we aren't Facebook but we love reactions too. They can give us valuable insights on how to improve what we're doing. Would you tell us how you feel about this article?

We use cookies to personalize our service and to improve your experience on the website and its subdomains. We also use this information for analytics.

More info