Android is not just another Linux distribution for mobile devices. While you develop for Android, you're not all that likely to meet the Linux kernel itself. The developer-facing side of Android is a platform that abstracts away the underlying Linux kernel and is programmed via Java. From a high-level view, Android possesses several nice features:
An application framework providing a rich set of APIs to create various types of applications. It also allows the reuse and replacement of components provided by the platform and third-party applications.
The Dalvik virtual machine, which is responsible for running applications on Android.
A set of graphics libraries for 2D and 3D programming.
Media support for common audio, video, and image formats such as Ogg Vorbis, MP3, MPEG-4, H.264, and PNG. There's even a specialized API for playing back sound effects, which will come in handy in our game development adventures.
APIs for accessing peripherals such as the camera, Global Positioning System (GPS), compass, accelerometer, touch screen, trackball, and keyboard. Note that not all Android devices have all of these peripherals—hardware fragmentation in action.
There's of course a lot more to Android than the few features I just mentioned. For our game development needs, these features are the most relevant, though.
Android's architecture is composed of a stack of components, and each component builds on the components in the layer below it. Figure 1-1 gives an overview of Android's major components.
OpenGL | ES
Notification Manager android runtime
Flash Memory Driver
Binder (IPC) Driver
Figure 1-1. Android architecture overview
Starting from the bottom of the stack, you can see that the Linux kernel provides the basic drivers for the hardware components. Additionally, the kernel is responsible for such mundane things as memory and process management, networking, and so on.
The Android runtime is built on top of the kernel and is responsible for spawning and running Android applications. Each Android application is run in its own process with its own Dalvik virtual machine.
Dalvik runs programs in the DEX bytecode format. Usually you transform common Java .class files to the DEX format via a special tool called dx that is provided by the software development kit. The DEX format is designed to have a smaller memory footprint compared to classic Java .class files. This is achieved by heavy compression, tables, and merging of multiple .class files.
The Dalvik virtual machine interfaces with the core libraries, which provide the basic functionality exposed to Java programs. The core libraries provide some but not all of the classes available in Java SE through the use of a subset of the Apache Harmony Java implementation. This also means that there's no Swing or Abstract Window Toolkit (AWT) available, nor any classes that can be found in Java ME. However, with some care, you can still use many of the third-party libraries available for Java SE on Dalvik.
Before Android 2.2 (Froyo), all bytecode was interpreted. Froyo introduces a tracing JIT compiler, which compiles parts of the bytecode to machine code on the fly. This increases the performance of computationally intensive applications considerably. The JIT compiler can use CPU features specifically tailored for special computations such as a dedicated Floating Point Unit (FPU).
Dalvik also has an integrated garbage collector (GC). It's a mark-and-sweep nongenerational GC that has the tendency to drive developers a tad bit mad at times. With some attention to details, you can peacefully coexist with the GC in your day-today game development, though. The latest Android release (2.3) has an improved concurrent GC, which relieves some of the pain. We'll investigate GC issues in more detail later in the book.
Each application running in an instance of the Dalvik VM has a total of 16MB to 24MB of heap memory available. We'll have to keep that in mind as we juggle our image and audio resources.
Besides the core libraries, which provide some Java SE functionality, there's also a set of native C/C++ libraries that build the basis for the application framework (located in the next layer of Figure 1-1). These system libraries are mostly responsible for the computationally heavy tasks such as graphics rendering, audio playback, and database access, which would not be so well suited for the Dalvik virtual machine. The APIs are wrapped via Java classes in the application framework, which we'll exploit when we start writing our games. We'll abuse the following libraries in one form or another:
Skia Graphics Library (Skia): This software renderer for 2D graphics is used for rendering the UI of Android applications. We'll use it to draw our first 2D game.
OpenGL for Embedded Systems (OpenGL ES): This is the industry standard for hardware-accelerated graphics rendering. OpenGL ES 1.0 and 1.1 are exposed in Java on all versions of Android. OpenGL ES 2.0, which brings shaders to the table, is supported from only Android 2.2 (Froyo) onward. It should be mentioned that the Java bindings for OpenGL ES 2.0 are incomplete and lack a few vital methods. Also, the emulator and most of the older devices that still make up a considerable share of the market do not support OpenGL ES 2.0. We'll be concerned with OpenGL ES 1.0 and 1.1, to stay compatible as much as possible.
OpenCore: This is a media playback and recording library for audio and video. It supports a good mix of formats such as Ogg Vorbis, MP3, H.264, MPEG-4 and so on. We'll be mostly concerned with the audio portion, which is not directly exposed to the Java side but wrapped in a couple of classes and services.
FreeType: This is a library to load and render bitmap and vector fonts, most notably the TrueType format. FreeType supports the Unicode standard, including right-to-left glyph rendering for Arabic and similar peculiarities. Sadly, this is not entirely true for the Java side, which to this point does not support Arabic typography. As with OpenCore, FreeType is not directly exposed to the Java side but is wrapped in a couple of convenient classes.
These system libraries cover a lot of ground for game developers and perform most of the heavy lifting for us. They are the reason why we can write our games in plain old Java.
Note: Although the capabilities of Dalvik are usually more than sufficient for our purposes, at times you might need more performance. This can be the case for very complex physics simulations or heavy 3D calculations—for which we would usually resort to writing native code. I do not cover this aspect in this book. A couple of open source libraries for Android already exist that can help you stay on the Java side of things. See http://code.google.eom/p/libgdx/ for an example. Also worth noting is the excellent book Pro Android Games by Vladimir Silva (Apress, 2009), which goes into depth about interfacing with native code in the context of game programming.
The application framework ties together the system libraries and the runtime, creating the user side of Android. The framework manages applications and provides an elaborate framework within which applications operate. Developers create applications for this framework via a set of Java APIs that cover such areas as UI programming, background services, notifications, resource management, peripheral access, and so on. All core applications provided out of the box by Android, such as the mail client, are written with these APIs.
Applications, whether they are UIs or background services, can communicate their capabilities to other applications. This communication enables an application to reuse components of other applications. A simple example is an application that needs to take a photo and then perform some operations on it. The application queries the system for a component of another application that provides this service. The first application can then reuse the component (for example, a built-in camera application or photo gallery). This significantly lowers the burden on programmers and also enables you to customize a plethora of aspects of Android's behavior.
As game developers, we will create UI applications within this framework. As such, we will be interested in an application's architecture and life cycle as well as its interactions with the user. Background services usually play a small role in game development, which is why I will not go into details about them.
Was this article helpful?