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:
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.
Viewlayer, 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
LiveDataelements taken from the
ViewModelautomatically observes the
Lifecyclestate 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
ViewModelnever references the
Viewdirectly and that the updates on the data are always done by the
Repositoryisn'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
Roomdatabase 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
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.
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.
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
Fragment that conforms to this new standard, you have to extend a
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.
Lifecycle events and can react through annotation. No method override is necessary.
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 will behave according to
Lifecycle state. If the observer's
Lifecycle state is
RESUMED, the observer is
active; otherwise, it is
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.
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
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.
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
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.