Overview and Application Patterns
To begin, we will discuss some history of the software and the Android OS. The Android operating system was initially developed by a startup company named Android Inc. in 2003 and purchased by Google in 2005. Google provided a lot of input into the end result of the Android OS and had a large influence in the architecture.
If you think back to 2005, AJAX was all the rage and this most likely had a substantial influence on the Android architecture since it responds more like an AJAX application than a desktop GUI application. The usual thought is that someone at Google wanted an operating system that acted more like a rich web application than usual. They also believed that these web applications would be the future of application development and wanted a platform that would natively support that idea.
Android is based on three fundamental architectural layers that are very distinct and separated.We will look at each of these layers more in-depth. They are:
- 1. Linux: The Linux layer is a stripped down and modified version of Linux designed for Android devices
- 2. Application Infrastructure: The application infrastructure layer contains the Dalvik Java virtual machine, web browser, SQLite database, API connections, infrastructure connections and Java APIs.
- 3. Application: The application layer is the Google-made Android applications that run as stand-alone apps or can be used as the foundation for further application development.
The Linux Layer
It makes sense that the developers at a small start-up company would choose to use Linux as their new operating system platform instead of trying to write one from scratch. They simply would not have had the time or resources to make that possible.It also isn’t a practical idea to try to reinvent the wheel for certain aspects of the OS when you can take the foundation and implement your own changes. You can see this as the prevalent idea in other operating systems such as previous versions of Windows being built on DOS or Mac OS X having a FreeBSD foundation.
However, the problem they needed to solve was not an easy one. At the time that Android Inc. was creating their new mobile operating system, Linux could not run on mobile devices. These target devices just didn’t have the high level of RAM or persistent memory available to support such a complex operating system. Mobile device CPUs were also very weak, so these developers knew they needed to create their Linux-based system with a much smaller footprint and resource requirements than what Linux natively used currently.
The solution was to strip Linux down to its essential parts, the kernel, which is required for the system to run and remove a lot of the optional functionality that was unnecessary. Some components were kept in, such as the Ash shell and IPTables because they would be need for the OS to be functional but most choices on what to keep where guided by the overall size of the footprint the component would leave. This left the developers with a base to begin working with that was small enough to run on their desired mobile platform.
Next, hardware support had to be added since many features were available to mobile devices that did not exist in a desktop-hardware operating system. Overall, support was added for the smaller screen sizes, different RAM modules, touch-screen functionality, different keyboard configurations and side buttons as well as network support for WiFi and mobile providers. Developers had to think about the mobile hardware setup and create the necessary input functionality so the user would be able to interact with the system appropriately without a standard keyboard and mouse.
Ultimately, while this history is useful information, if your goal is to create simple Android applications for the marketplace, you will probably never touch the underlying Linux foundation. Most of what will be important to you resides in the application infrastructure layer. However, if you have been thinking about working on the Android Open Source Project (AOSP) to create further functionality for the operating system you will need to understand this foundational system intimately.
The Application Infrastructure Layer
If an experienced developer is looking at the application infrastructure layer, they may notice some similarities between foundational parts of the Android OS and Apple’s iOS since the two operating systems share a common code-base ancestor. However, many of the architecture decisions have been very different between the two, which has resulted in two very unique systems.
Let’s compare: Apple’s foundational programming language and runtime is Objective C++, which is a natural choice for an OS built on FreeBSD. Objective C++ is like regular C++ with a custom preprocessor and the addition of linguistical constructs. This was a logical choice for Apple since they probably needed to add in some custom code handling between their system and FreeBSD. Therefore we can see that Apple’s applications are written in a language that is pretty much the same as the underlying OS itself.
On the other hand, Android is very different. Android applications are written in Java, which is very different from the underlying Linux platform that is written in C++. So why was this decision made? The main reason seems to be the differences in hardware. Apple can write their iOS system for a closed set of hardware that is their own design and can plan for hardware compatibility. Android does not have that luxury. They ultimately needed a system that would make the same application binaries work without changes across multiple different devices. Google does not get to control the Android hardware manufacture process the way Apple can. A good example of this is the three possible processor types that we currently have available for Android devices: x86, ARM and Atom. These three processors are incompatible at the binary level and thus you would not be able to write an application that would be able to convert to all three.
If the Android operating system had followed the Apple path, application developers would need to create different versions of their application for different hardware sets. By executing everything in the Java container, the binaries can be executed by a software container which isolates them from the hardware that it is running on. This was likely the driving factor behind Google’s decision to use Java as its primary application development language and runtime.
The next big roadblock was created from this decision to use Java. Google needed to decide what version of the Java virtual machine (JVM) to use. The standard JVM was not an option because of resource constraints and they were not happy with the current ME JVM for mobile devices. Therefore, Google decided to create a custom version of the JVM called Dalvik JVM. Since this was a custom build of JVM there are some differences in features and functionalities from the regular JVM. Here are some of the differences:
- Dalvik is optimized for running multiple JVM processes simultaneously
- Dalvik uses refister-based architecture instead of stack-based architecture like other JVMs which speeds up the execution and reduces the binary size.
- It uses DEX formatting for storing application binaries instead of JAR and Pack200 formats which creates smaller binaries.
- You can run several independent Android applications within a single JVM process
- Dalvik uses its own instruction set and not standard JVM byte code
- Application execution can span across several JVM processes. To support this they had to add:
- Special object serialization based on Parcel and Parcelable classes
- A special way to execute inter process calls (IPC) based on Android Interface Definition Language (AIDL)
- JIT compilation was added in Android 2.2 Dalvik which greatly improved execution speed for commonly used applications
As you can see, many of the changes in Google’s custom JVM were designed to make application binaries smaller, run faster and the overall system more robust. Google also revised the standard Java JDK API packages and removed a lot of extra packages and added in some custom packages that developers can use as well as some useful open-source packages such as Bouncy Castle crypto API and HTTPClient which support client-side HTTP/HTTPS.
In part 1 of this tutorial, we examined the first two underlying foundation layers that make up the Android operating system. In part 2, I will talk about architectural styles and patterns so you can have a better understanding of how certain parts of the system work and how you can use application design patterns to create better Android applications.Why is learning design patterns important? When learning a new architecture or system, design patterns allow us to use previous development knowledge and put it to use in a new environment. Android does not have any documented patterns but that does not mean we cannot use a number of patterns in our Java development for Android.
The Application Layer
The Android application architecture is a framework-based application system instead of a free-style application system. What is the difference? Free-style applications that are written in Java begin with a class that contains a main() method and the developer inserts the code into the main() method to do whatever they want. The opposite of this is a framework-based application that is based on an existing framework, which cannot run without access to the framework. Examples of this would be Java web applications where a servlet implements an interface or extends one of its subclasses, or an Eclipse RCP application if the developer has extended the Editor or View classes. A non-Java example would be .NET application languages such as C#, which require access to the .NET framework and class library to run.
Many developers feel that framework-based application systems limit what the developer can do or require certain functions to be completed in a proscribed way. However, the trade-off is the elimination of a lot of “boilerplate” code and the enforcement of standards and design patterns. There are many application frameworks available for Java and the developers for Android designed one specifically for this new system. This unique framework is designed to take advantage of the Android/Java memory management system.
Let’s take a look at how Java usually works. In Java an object that has been created will be kept in memory until it is destroyed or marked for garbage collection. The system will not destroy something that isn’t currently in use just because you aren’t using it. In Android the system works differently. If you hide a GUI so that it is not visible on the screen there is no guarantee that it won’t be marked for garbage collection and destroyed. It might be kept if Android has enough memory available but if the system needs that memory it could be destroyed. This also applies to processes that may be running in the system, so if it doesn’t have a GUI showing currently on the screen it could be terminated by the Android OS.
Here is an example: we open an application an access GUI screen 1 and then GUI screen 2. GUI screen 1 is no longer showing on the screen and may be destroyed from memory. If this application screen has information that is necessary for the application the user may return to it later.The problem then is that the programmer cannot have any reassurance that the screen will still be there when the user wants to return to it. How do we solve this problem? The Android system was designed with lifecycle methods in certain classes that an application developer has to implement to create the application. These methods are called by the Android framework and work during predefined transitional moments such as when a GUI is being hidden. The developer can then create the logic that is used for storing and retrieving the state of objects inside of those methods.
Another result of this type of system that is Android enforces a “share nothing” architectural style where applications can invoke each other and communicate but only in an explicit way. There is no shared state memory that can be used between them. Since we have to handle hidden GUIs this way and you often have a “back” button, the Android system creates a GUI stack where the current, visible GUI is at the top and all others are pushed down. As you press the “back” button you can move through this stack of GUI objects. This is sometimes called the “activity stack” or “back stack” in Android documentation.
In the section above I mentioned that Android applications can only communicate in a declarative way. There are a few ways in the application framework that applications can send messages:
- Message passing using the Intent class
- Late binding and Inter-process Procedure Communication (IPC) for invoking remove (AIDL) Services
- Late binding with methods calls for accessing ContentProviders and local Services
- Publish/subscribe (pub/sub) using the Intent class and BroadcastReceiver class
Android applications follow a standard Model-View-ViewModel (MVVM) type of architectural pattern because of the way it handles relationships between the GUI and the logic that supports it. The MVVM pattern is the latest architecture for GUI applications at the moment and was created as an attempt to solve the problem between developer skillsets. Most developers may have a lot of talents but GUI design and development may not be one of them. This is usually the work of GUI designers that are more artists and graphic designers than developers and they spend their time studying user experience and the look-and-feel of your application instead of solving the problem that developers do. However, Swing and MFC systems simply do not allow the separation of the GUI and logic code. This is where the MVVM pattern comes in because it can overcome this problem and allow us to separate the duties. GUI development can be done by a GUI designer in a language such as XML, that is more suited to this task and the logic code behind the GUI can be developed as a ViewModel component. The functional relationships between the GUI and ViewModel are implemented through bindings that define the rules for the functionality such as “call
MethodA() if button A is clicked”. These bindings can be both declarative and written in the code.The MVVM pattern has become the industry standard for how modern GUIs should be written. Look at Microsoft’s Silverlight, Windows Presentation Foundation, Oracle’s JavaFX and Adobe Flex. All of these are examples of the Model-View-ViewModel in action.
As you can see, the application layer of the Android system is a busy and complex place and we have only scratch the surface here. In the last installment of this series we will get more in-depth with the main parts of an Android application and dig deeper into some of the things discussed in this article.