Brian Long Consultancy & Training Services
Ltd.
January 2012
To get an understanding of how a simple Android applications works we’ll take a generalised overview of its architecture.
An Android application is made up of various building blocks, each of which is designed to fulfil a specific type of goal. These are activities, services, broadcast receivers and content providers:
Android.App.Activity
class.Android.App.Service
.Android.Content.BroadcastReceiver
.Android.Content.ContentProvider
.Applications have as many or as few of these components as befit the application’s requirements. The simplest application has just one activity.
An application does not have to implement all the above components it needs – it can make use of, say, activities and content providers from other applications that have been installed or from the basic Android system. A simple example would be browsing to a web site URL. There’s no real need to implement an activity that can display a web page, as your Android device will already have one (the built in browser app). You can invoke that existing activity instead.
In the project the class containing the code inherits from Android.App.Activity
and so the application contains one activity component.
These application components can communicate in a few ways but the pervading communication
mechanism is Android.Content.Intent
. An intent can be used to start
an activity, communicate with a service or be sent to an interested broadcast receiver.
Since applications can make use of external components it follows that intents operate
between applications. An intent represents a form of late (or run-time) binding
between application components; it’s a type of structured message.
An explicit intent knows the application component it is to work with – it has the class name or type. An implicit intent does not; it just knows what you want to do and tries to find a component to satisfy that requirement.
Because an application is a collection of these potentially autonomous components, how does Android know what to do when an application is started? Moreover, how does Android know what components are implemented by the application so it can access them? Well, in the Android world the Android manifest file, AndroidManifest.xml, answers these and other questions.
The manifest file can contain lots of information to help the Android OS work well with your application. It allows you to describe your application components, identify what component will start when the application is launched by Android, specify any permissions required by the application, identify the minimum Android platform required, define what any published broadcast receivers can respond to, identify the application icon, specify a default application theme and much more besides.
Every Android project has an Android manifest file, which is stored in the Properties
project subfolder, called Properties\AndroidManifest.xml
. The manifest from the
project we've generated looks something like this:
In among this smattering of XML attributes, noteworthy things include:
android:label
attribute in the
application
elementandroid:icon
attribute in the application
elementandroid:label
attribute in the
activity
elementMainActivity
is the activity to launch when the
application starts: the intent-filter
element in the activity
element with the specific action
and category
elements
within. Without this intent filter element, this would just be a declaration of
some activity in the application.Several of the attributes mentioned above refer to string or drawable resources and we'll see more about this syntax later.
It is important to be aware of how the Android OS manages the components in an application,
because under certain low-memory circumstances, they can be unilaterally terminated.
Since the sample application only has an activity in it we’ll look at the lifecycle
of the Activity
class. At each of the various milestones of the activity
lifecycle a virtual method executes, thereby allowing you to override the method and run
custom code at that point.
The entire lifetime of an activity goes from its creation, where
onCreate(Bundle)
is called, to its destruction, marked by onDestroy()
. So basic initialisation
and loading of the UI (via the assignment to ContentView
as per
the earlier code snippet) should occur in onCreate(Bundle)
and general cleanup in onDestroy()
.
To mark its display on the screen onStart()
is called, and the activity
is now considered paused. When no longer visible onStop()
is called
and it is considered stopped. If it becomes visible again onRestart()
is executed before onStart()
gets another look-in.
After becoming visible the activity will be brought to the foreground (given focus),
as indicated by onResume()
. The activity is now considered active or
running. When something knocks it out of the foreground (another activity coming
to the foreground) onPause()
runs, and it is considered paused once
more. If it comes to the foreground again, this pair starts its cycle again. If
it ends up being terminated, it goes through onStop()
and onDestroy()
.
So, when an activity is started, onCreate(Bundle)
,
onStart()
and onResume()
are called to bring it to the foreground. When something
else comes to the foreground onPause()
runs and there are potentially
several onResume()
/onPause()
loops. When it leaves the
screen the activity’s onStop()
runs. If brought back to the foreground
we have onRestart()
, onStart()
and onResume()
.
Eventually after onStop()
you will get onDestroy()
.
Having got the idea of that it is important to remember that a phone is not a memory-rich
arena and sometimes memory comes under pressure. At such times the Android OS has
the opportunity to kill off activities that are not in the foreground. Typically
this will involve killing activities that have executed onStop()
and
are waiting off-screen. However given enough extreme memory pressure Android will
also kill off activities that are still visible but not foreground, such as activities
sitting behind a dialog, i.e. those whose onPause()
has run (although
this is no longer true in Honeycomb, Android 3.0).
If your activity gets killed through memory pressure it will allow you to save state
by running onSaveInstanceState(Bundle)
just before the termination.
You don’t need to worry about the controls (or widgets as they're called in
Android) as their state is automatically saved
and later restored, but you can save any other state data in the Bundle
object passed to this routine. Whenever the activity is next invoked state can be
restored from the Bundle
object passed to onRestoreInstanceState(Bundle)
,
which will be called after onStart()
and before onResume()
.
Alternatively you can just use the Bundle
object passed to onCreate(Bundle)
.
In the case of services the lifetime is simpler than for activities as there is no UI to be displayed and hidden. However, we’ll not worry about the specifics for services in this article.
In a simple case where there is no special state that requires saving and no UI-specific
code that needs to execute when the activity is shown and hidden, or brought to
the foreground and sent to the background, then you just need to load your UI in
the onCreate(Bundle)
and do any other setup.
When an activity is running, normal device behaviour when pressing the Home
button is for the activity to be sent to the background, so onPause()
and onStop()
execute. If you switch back to the activity with a long
press on Home
or by pressing a shortcut to the application then the
activity is resumed, thereby calling onRestart()
, onStart()
and onResume()
.
However if you press Back
on an activity, it is (by default)
killed off, so onPause()
, onStop()
and onDestroy()
get called. You can alter this default behaviour by overriding the onBackPressed()
virtual method. An activity can terminate itself by calling finish()
.
On a phone where hitting the power button enables the soft lock and turns of the
display, this pauses the activity so onPause()
is called immediately.
We need to take a look at how the Android eco-system deals with resources, from
UI definitions to text strings to icons. These can all be externalised from the
code into a res
subfolder within the Android project folder.
Externalising resources allows you to readily support different configurations
available on various Android devices, which, for example, run at different resolutions
and/or with different screen densities. In the case of text strings, externalising
these facilitates localising them to additional languages in a fairly straightforward
manner.
Within the res
folder are a varying number of additional subfolders
containing different types of resources. The sample project has these resource subfolders:
drawable
: contains bitmap resources and special XML files that can
reference other drawable resources. Well, ok, this is not true. It could
have a drawable
subfolder, containing such files but in fact uses three
folders in place of drawable
(we'll come back to this idea
below):drawable-hdpi
: drawable resources specific to high density (hdpi) display
devices, in this case just the application icon file, icon.pngdrawable-mdpi
: drawable resources specific to medium density (mdpi)
display devices, in this case just the application icon file, icon.pngdrawable-ldpi
: drawable resources specific to low density (ldpi) display
devices, in this case just the application icon file, icon.pnglayout
: this is where you put your XML UI definition files. We’ll need
to take a closer look at UI layout files, but for now we just need to know that
any UI, mostly for an activity, is defined in an .xml file. The project's UI is
in a layout file called main.xml
.values
: contains XML files defining strings, styles and some other
less common resource types. The sample project has a string definition file, strings.xml
in this subfolder, containing string definitions in terms of names and values:
Android supports other kinds of resources that have their own subfolder names. You can read up on this at http://d.android.com/guide/topics/resources/providing-resources.html.
Note: the files and folders within the res
folder
hierarchy must all have lower case names, a restriction imposed by the Android
tool that processes the resources.
Note: The resource directory hierarchy defaults to being a project
subfolder called res
but this can be updated in the project options
on the Android property sheet.
All these resources need to be accessible from the code, and the R
class helps achieve this. As you add resources into the res
directory
tree, a post-build operation updates the to contain various nested classes with
their own members that map onto each resource. This R
class is not
found in a source file in the project as it is auto-generated during the build process.
On the subject of this post-build auto-generated R
class:
R
class is actually initially generated as a Java class as a side-effect
of the
Android Asset Packaging Tool (aapt.exe) in a source file called R.java in
the obj\Java\Debug
or obj\Java\Release
folder, depending
on which build configuration is active. As soon as this occurs, Oxygene for Java
translates this Java file into an Oxygene file called R.pas in the same folder.res
directory structure,
Code Completion (IntelliSense) won't see the identifiers until the next time you
compile, since the code is auto-generated in a post-build event.
The sample project has an R
class looking like this (although this
one has been slightly edited for brevity, such as having default constructors and
comments omitted):
You can see here that the icon image, the main activity layout resource, a button id and three strings each have integer identifiers defined. Every time you build your project this file is updated to account for any new resources you may have added.
In the sample project, the UI is loaded up with a call to:
This references the main.xml UI layout resource via its integer resource identifier
and assigns that to the activity's ContentView
property (though
see below for more on properties in Java and in Oxygene for Java).
Also in the activity's onCreate()
method:
This identifies a button widget via its id and asks the activity to locate the widget
for the button using this id. The resultant View
is typecast to a
Button
and assigned to a local variable. We'll see
later how the button id was defined.
Finally, in the button event handler we had:
This uses the id of one of the string resources and builds up a formatted string from it.
Note: Widgets defined in Android layout files do not have variables automatically declared in the source code. For any widgets you need to access in code you need to set up variables and assign them values in this manner.
The resources also need to be accessible from XML files, such as the Android
manifest file and layout files, or other resource files. The general form of
this was seen in the Android manifest file above:
"@resource_type/resource_id"
, for example:
In the sample project code you can see the activity's main layout being assigned with the statement:
However if you were to search for this ContentView
property in the
Android SDK documentation
you wouldn't find it. This is because Java does not support properties as a
language feature.
Properties are a way of allowing a method that reads a value and a method that writes a value (both with optional side effects) to be treated like a singular data item (with optional side effects), simplifying two methods into one property. A property is like a data field with side effects and can optionally be read-only or write-only by not having a setter method or getter method respectively in its definition.
In Java there are no properties, just the getter and setter methods. In the case
of an activity's layout, the available functionality is in fact a setter method
(actually a set of three overloaded methods) called setContentView()
,
and of course these can be found in the documentation.
When Oxygene sees a setFoo()
or getFoo()
method in a referenced
library, it immediately offers a property as if it were defined in terms of those
getFoo()
/setFoo()
methods. You then have the option of
using the property (as in the code in the sample project) as we would normally do in Delphi or C#, although you can still
use the original methods if you wish.
Java events are a little different to events that Delphi and .NET programmers may be familiar with. Indeed if you look at the sample project code you'll see an event handler being set up for the activity's button and it uses syntax that was added to support the Java way of dealing with events:
In the world of Java events are managed with interfaces. An interface, often with
a single method, is defined for the purpose of handling some event of some object.
In the case of a button, its click event is managed with the View.OnClickListener
interface and its OnClick()
method. To handle the event you need to
assign to the event property (OnClickListener
in the case of a button
click event, although this is an implied property and at the Java level we are
really dealing with the setOnClickListener()
method) an object that implements the interface.
One option would be to implement the required interface method in your activity
class and assign self
to the event property. This would work fine
for one button, but of course to handle the clcick event of multiple buttons
you'd quickly come unstuck as the activity can only implement a given interface
once.
You could also consider implementing the interface in a different dedicated class
for each button, but that would quickly become unwieldy. However a new shortcut
syntax in Oxygene 5 essentially does that very job, at the same time allowing you
to use a local method (or anonymous method or lambda expression) as the implementation
of the interface method. This inline interface implementation syntax uses the keywords
new interface
to create a new object implementing the specified interface
and then takes instruction as to how to implement each interface method. You can
read more on this subject in my article about inline interface implementation.
In the snippet above the syntax creates an object implementing View.OnClickListener
and specifies that the OnClick
method is to be implemented by the activity's
ButtonOnClick
method. You can equally use an anonymous method here
or a lambda expression. If the interface has more than one method you can use a
comma-separated list to stipulate what to do for each method of interest. Any
methods not listed will be given empty stub implementations.
In the case above the interface only has one method. Because of this we could simplify the statement using a permitted abbreviation and instead write:
As stated above one of the prime reasons to
externalise all the resources into the res
folder tree is to
support multiple configurations and multiple languages. This is enabled by using
additional directories with suffixes formed by one or more instances of a hyphen
(or dash, or minus sign) followed by a configuration qualifier.
There are config qualifiers for various configuration aspects, such as screen density, screen size, screen aspect, screen orientation and so forth. The resource directories without a suffix are the default resources. The ones with config qualifiers provide alternate resources for certain configurations on various devices.
Take, for example, the icon in the sample project. We saw earlier
that in fact there are three icons supplied in directories that all basically a
drawable
directory, but with config qualifiers applied for hdpi, mdpi
and ldpi screens. According to the Android UI guidelines, application launcher icons should
be 72x72 pixels on High Density (hdpi) screens, 48x48 pixels on Medium Density (mdpi)
screens and 36x36 on Low Density (ldpi) screens. The three default drawable directories
provide application icons of these dimensions for these three screen densities
using config-specific drawable
directories.
The 36x36 ldpi default application icon looks like this:
The 48x48 mdpi default application icon looks like this:
The 72x72 hdpi default application icon looks like this:
In the case of a resource directory for localised strings, the config qualifier specifies
a language (ISO
639-1 language code) optionally followed by a hyphen, an r
and a region (ISO 3166-1-alpha-2 region code), for example fr
(French) or fr-rCA
(French Canadian). The localised version of strings.xml
can have as many or as few of the strings translated as is necessary. Android will
always fall back on the default string if a translation is missing.
More information on providing alternative resources can be found in the Android SDK documentation at http://developer.android.com/guide/topics/resources/providing-resources.html#AlternativeResources.
The user interface of the sample project is defined in the file res\layout\main.xml
,
which looks like this:
When working with Oxygene for Java there is no visual UI designer; user interface layout is achieved by coding up XML files like the one above. When writing one of these files you will likely need to refer to the Android documentation to identify which attributes are permitted where, while getting used to it. However it is still a trial and error process, as you cannot see the effect of your layout until you run the application on a device or emulator.
Android programmers using Java and Eclipse do get a bit of a nod in the direction of a UI designer, but it’s not really much to be jealous of. Having talked to a Google representative, my understanding is that better UI design tools ought to be forthcoming now that they realise what a demand there is for them.
All that said there are UI designers out there. For example, DroidDraw from http://droiddraw.org is a free UI design tool that runs as a Java applet in the browser, although standalone executable versions are also available. You may find it useful, though it takes some getting used to. Be sure to follow the tutorials to learn how to use it.
Sticking with the raw manual creation strategy for the time being, let’s take a look at the layout file above.
Android UIs are hierarchical collections of Android.Views.View
descendants,
which typically reside in the Android.Widget
namespace. In the case
here there are two widgets: a layout widget and a control widget. There are various
layout widgets including LinearLayout
, RelativeLayout
,
AbsoluteLayout
, FrameLayout
and TableLayout
.
These have differing ways of organising the control widgets you place in them.
The sample layout uses a linear layout widget with a vertical orientation, so each
control added will be placed below the previous one. Each widget needs a width and
height specification. fill_parent
is descriptive enough, but you can
also use wrap_content
to make it as large as is needed based on the
controls or content within.
The only control (or widget) in the linear layout is a Button
, set
to be as wide as the screen (well, actually as wide as its parent, which was set
to be as wide as the screen, given the linear layout was the top level view and
also set to be as wide as its parent). The button’s text is set using
the syntax for reading a string resource from the values\strings.xml
file.
That leaves the id
attribute. This uses a slightly different syntax
to define a new identifier. MyButton
does not exist until this id
attribute definition, and the +
sign in the value tells Android to
make a new resource ID, which will be added into the R
class.
Indeed if you look back at this project’s R
class you will see the MyButton
ID defined in the Id
nested class. This newly defined ID can be referred
to elsewhere in the layout. For example if we were using a RelativeLayout
instead of a LinearLayout
, another widget could indicate it is to the
right of MyButton
using an attribute such as:
Additionally, the code can access the widget by passing the ID to
findViewById()
. The code in the sample project does this to get
a reference to the button so that it can set up the Click
event handler
and update the button’s Text
property when the button gets clicked.
So that concludes the look through the simple template Android app project, looking at the application lifecycle, the way resources are managed, how the UI is built and how the code access the UI.
This article has shown how Oxygene for Java facilitates utilization of existing Object Pascal programming ability to start building applications for Android devices in a very capable manner, providing a convenient means of starting to write Android apps without having to learn an entirely new programming language and development environment.
Of course, an understanding of the Android libraries needs to be built up in order to do the job well, but working with a language you are familiar with helps ease the transition to a new target platform.
The Android documentation site is at http://developer.android.com (or the shorter URL of http://d.android.com).
The Android SDK documentation is at http://d.android.com/reference.
The Android UI Guidelines are at http://d.android.com/guide/practices/ui_guidelines.
If you wish to make any comments on this article, your best options are to comment on the blog post that announced it, use the Contact Me form or email me at .
If you find this article useful please consider making a Paypal donation. It will be appreciated however big or small it might be and will encourage Brian to continue researching and writing about technically interesting topics in the future.
Brian Long has spent the last 1.6 decades as a trainer, trouble-shooter and mentor focusing on the Delphi, Oxygene, C# and C++ languages, and the Win32, .NET and Mono platforms, recently adding iOS and Android onto the list. In his spare time, when not exploring the Chiltern Hills on his mountain-bike or pounding the pavement in his running shoes, Brian has been re-discovering and re-enjoying the idiosyncrasies and peccadilloes of Unix-based operating systems. Besides writing a Pascal problem-solving book in the mid-90s he has contributed chapters to several books, written countless magazine articles, spoken at many international developer conferences and acted as occasional Technical Editor for Sybex. Brian has a number of online articles that can be found at http://blong.com and a blog at http://blog.blong.com.
© 2012 Brian Long Consulting and Training Services Ltd. All Rights Reserved.
Go back to the top of this page
Go back to start of this article