Android Application Architecture

An application architecture is a consistent plan that needs to be made before the development process starts. This plan provides a map of how the different application components should be organized and tied together. It presents guidelines that should be followed during the development process and forces some sacrifices that in the end will help you to construct a well-written application that’s more testable, expandable, and maintainable.

Good architecture takes many factors into consideration, especially the system characteristics and limits. There are many different architectural solutions out there, all of them with pros and cons. However, some key concepts are common between all visions.

Until the last Google I/O, the Android system didn’t recommend any specific Architecture for application development. That means that you were completely free to adopt any model out there: MVP, MVC, MVPP, or even no pattern at all. On top of that, the Android framework didn’t even provide native solutions for problems created by the system itself, specifically the component’s lifecycle.

So, if we wanted to adopt a Model View Presenter pattern on your application, we needed to come up with your own solution from scratch, writing a lot of boilerplate code, or adopt a library without official support. And that absence of standards created a lot of poorly written applications, with codebases that were hard to maintain and test.

After 12 long years, the Android team finally decided to listen to our complaints and to help us with this problem.

2. Android Architecture

The new Android Architechture Guide defines some key principles that a good Android application should conform to and also proposes a secure path for the developer to create a good app.According to the guide, a good Android application should provide a solid separation of concerns and drive the UI from a model. Any code that does not handle a UI or operating system interaction should not be in an Activity or Fragment, because keeping them as clean as possible will allow you to avoid many lifecycle-related problems. After all, the system can destroy Activities or Fragments at any time. Also, the data should be handled by models that are isolated from the UI, and consequently from lifecycle issues.

The New Recommended Architecture

The architecture that Android is recommending cannot be easily labeled among the standard patterns that we know. It looks like a Model View Controller pattern, but it is so closely tied to the system’s architecture that it’s hard to label each element using the known conventions. This isn’t relevant, though, as the important thing is that it relies on the new Architecture Components to create a separation of concerns, with excellent testability and maintainability. And better yet, it is easy to implement.

To understand what the Android team is proposing, we have to know all the elements of the Architecture Components, since they are the ones that will do the heavy lifting for us. There are four components, each with a specific role: Room, ViewModel, LiveData, and Lifecycle. All of those parts have their own responsibilities, and they work together to create a solid architecture. Let's take a look at a simplified diagram of the proposed architecture to understand it better.

As we can see, we have three main elements, each one with its responsibility.

  1. The Activity and Fragment represent the View layer, which doesn't deal with business logic and complex operations. It only configures the view, handles the user interaction, and most importantly, observes and exhibits LiveData elements taken from the ViewModel.
  2. The ViewModel automatically observes the Lifecycle state of the view, maintaining consistency during configuration changes and other Android lifecycle events. It is also demanded by the view to fetch data from the Repository, which is provided as observable LiveData. It is important to understand that the ViewModel never references the View directly and that the updates on the data are always done by the LiveData entity.
  3. The Repository isn't a special Android component. It is a simple class, without any particular implementation, which is responsible for fetching data from all available sources, from a database to web services. It handles all this data, generally transforming them to observable LiveDataand making them available to the ViewModel.
  4. The Room database is an SQLite mapping library that facilitates the process of dealing with a database. It automatically writes a ton of boilerplate, checks errors at compile time, and best of all, it can directly return queries with observable LiveData.

The Observer Pattern is one of the bases of the LiveData element and Lifecycle aware components. This pattern allows an object to notify a list of observers about any changes on its state or data. So when an Activity observes a LiveData entity, it will receive updates when that data undergoes any kind of modification.

Another Android recommendation is to consolidate its architecture using a Dependency Injection system, like Google’s Dagger 2 or using the Service Locator pattern.

Architecture Components

We must dive deep into the aspects of the new components to be able to really understand and adopt this model of architecture. Due to the complexity of each element, in this article, we’ll only talk about the general idea behind each one and look at some simplified code snippets. We’ll try to cover enough ground to present the components and get you started. But fear not, because future articles in this series will dig deep and cover all the particularities of the Architecture Components.

Lifecycle-Aware Components

Most of the Android app components have lifecycles attached to them, which are managed directly by the system itself. Until recently it was up to the developer to monitor the components’ state and act accordingly, initializing and ending tasks at the appropriate time. However, it was really easy to get confused and make mistakes related to this type of operation. But the android.arch.lifecycle package changed all that.

Now, Activities and Fragments have a Lifecycle object attached to them that can be observed by LifecycleObserver classes, like a ViewModel or any object that implements this interface. That means that the observer will receive updates about the state changes of the object that it is observing, like when an Activity is paused or when it is starting. It can also check the current state of the observed object. So it's much easier now to handle operations that must consider the framework lifecycles.

For now, to create an Activity or Fragment that conforms to this new standard, you have to extend a LifecycleActivity or LifecycleFragment. However, it's possible that this won't always be necessary, since the Android team is aiming to completely integrate these new tools with its framework.

The LifecycleObserver receives Lifecycle events and can react through annotation. No method override is necessary.

The LiveData Component

The LiveData component is a data holder that contains a value that can be observed. Given that the observer has provided a Lifecycle during the LiveData instantiation, LiveData will behave according to Lifecycle state. If the observer's Lifecycle state is STARTED or RESUMED, the observer is active; otherwise, it is inactive.

LiveData knows when the data was changed and also if the observer is active and should receive an update. Another interesting characteristic of the LiveData is that it's capable of removing the observer if it's in a Lifecycle.State.DESTROYED state, avoiding memory leaks when observed by Activities and Fragments.

The ViewModel Component

One of the most important classes of the new Architecture Components is the ViewModel, which is designed to hold data that is related to the UI, maintaining its integrity during configuration changes like screen rotations. The ViewModel is able to talk with the Repository, getting LiveData from it and making it available in turn to be observed by the view. ViewModel also won't need to make new calls to the Repository after configuration changes, which optimizes the code a lot.

The Room Component

Android supported SQLite from the start; however, to make it work, it was always necessary to write a lot of boilerplate. Also, SQLite didn’t save POJOs (plain-old Java objects), and didn’t check queries at compile time. Along comes Room to solve these issues! It is an SQLite mapping library, capable of persisting Java POJOs, directly converting queries to objects, checking errors at compile time, and producing LiveDataobservables from query results. Room is an Object Relational Mapping library with some cool Android extras.

Until now, you could do most of what Room is capable of using other ORM Android libraries. However, none of them are officially supported and, most importantly, they can't produce LifeData results. The Roomlibrary fits perfectly as the persistent layer on the proposed Android Architecture.

To create a Room database, you'll need an @Entity to persist, which can be any Java POJO, a @Daointerface to make queries and input/output operations, and a @Database abstract class that must extend RoomDatabase.

Conclusion

The standardized architecture proposed by Android involves a lot of concepts. We can’t expect to have a complete understanding of this topic yet. After all, we’re merely introducing the theme. But we certainly have enough knowledge by now to understand the logic behind the architecture and the roles of the different Architecture Components.

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.