Brian Long Consultancy & Training Services
Ltd.
May 2011
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. 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 native Android world the AndroidManifest.xml file 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 and much more besides.
However with Mono for Android a number of the basic aspects of the manifest file are dealt with using attributes instead. Certainly, publishing the application components and identifying which one will be launched on start-up are exposed through attributes, which fits with the .NET ethos.
If you look at the activity in the project you can see the class is decorated with
an instance of ActivityAttribute
, which is used to specify a descriptive
label and an icon for the activity and to specify it is the entry point of the application
when launched.
[Activity(Label = "MonoAndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")]
public class Activity1 : Activity
{
...
}
We’ll come back to the odd-looking icon reference syntax shortly
It is possible, and often necessary, to add an Android manifest file to your project from the Project Properties pages. If you do this the manifest-related attributes will have their represented values merged with the project’s android manifest file during the post-build packaging process.
The important thing to know about the Android manifest file right now is that it controls how the Android OS can interact with your application and learn about its capabilities and requirements.
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, 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 SetContentView()
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 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 just now.
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()
.
If you press Back
on an activity, though, the activity 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 Resources 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 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 Resources 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
be compiled into drawable resources. In the sample project we have a simple 72x72
image file that represents the application icon: Icon.png.Layout
: this is where you put your XML UI definition files, which,
for Mono for Android, have an .axml suffix. 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 as XML in an .axml file.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:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="Hello">Hello World, Click Me!</string>
<string name="ApplicationName">MonoAndroidApplication1</string>
</resources>
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
(though take note that the Resources
group directory is called res
when building Android apps with Java).
All these resources need to be accessible from the code, and the Resource
class, defined in Resource.Designer.cs in the Resources
folder, helps
achieve this. As you add resources into the resources directory tree, a post-build
operation updates the Resource
class to contain various nested classes
with their own members that map onto each resource. The sample project has a Resource
class looking like this (although this one has been slightly edited for brevity,
such as having default constructors and comments omitted):
public partial class Resource
{
public partial class Drawable
{
public const int Icon = 2130837504;
}
public partial class Id
{
public const int MyButton = 2131034112;
}
public partial class Layout
{
public const int Main = 2130903040;
}
public partial class String
{
public const int ApplicationName = 2130968577;
public const int Hello = 2130968576;
}
}
You can see here that the icon image, the main activity layout resource and the two 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:
SetContentView(Resource.Layout.Main);
This references the Main.axml UI layout resource via its integer resource identifier.
Going back to the activity attribute from earlier:
[Activity(Label = "MonoAndroidApplication1", MainLauncher = true, Icon = "@drawable/icon")]
public class Activity1 : Activity
{
...
}
This does not use the possibly expected Resource.Drawable.Icon
to reference
the icon image, but that’s because the value of the attribute’s Icon
property is destined for the Android manifest file, an XML file. In XML file you
can reference the resource that is accessed by Resource.Drawable.Icon
in code using @drawable/icon
.
If we were being pedantic we might want to change the activity label in the attribute to reference the application name as defined by the string resource – that’s what the string resources are there for, after all. To access an individual string resource from the strings XML file follows the pattern shown in this example:
[Activity(Label = "@string/ApplicationName", MainLauncher = true, Icon = "@drawable/icon")]
public class Activity1 : Activity
{
...
}
Also note that the sample project makes use of another literal string, in the button event handler. This is not demonstrating best practice, but makes things clearer and easily understandable when looking at the code for the first time.
As stated above one of the prime reasons to
externalise all the resources into the Resources
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. This 72x72 icon is, according
to the Android UI guidelines, suitable as a launcher icon on a
device with a High Density (hdpi) screen, but it is supplied as the only icon (therefore
the default icon). It might be prudent to also supply a 48x48 icon and a 36x36 icon
to satisfy the requirements of Medium Density (mdpi) and Low Density (ldpi) screens.
To accomplish this, create images in those dimensions with the same name (Icon.png)
and place them in Drawable-mdpi
and Drawable-ldpi
subfolders,
respectively, under Resources.
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.
The user interface of the sample project is defined in the file Resources\Layout\Main.axml
,
which looks like this:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<Button
android:id="@+id/MyButton"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/Hello"
/>
</LinearLayout>
When working with Mono for Android 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 there is a certain amount of IntelliSense or Code Completion available in the editor and so this isn’t entirely arduous. 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 will be forthcoming now that they realise what a demand there is for them. In the case of Mono for Android, this is also likely to occur.
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.
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 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 Resource
class.
Indeed if you look back at this project’s Resource
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:
android:layout_toRightOf="@id/MyButton"
Additionally, the code can access the widget by passing the ID to FindViewById<t>()
or FindViewById()
. The code in the sample project does this to get
a reference to the button, so 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 Mono for Android facilitates utilization of existing C# .NET programming knowledge to start building applications for Android devices in a very capable manner. The Mono for Android SDK provides 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 UI framework.
Business logic can potentially be reused in applications running on Android if partitioned sensibly, but clearly an entirely different UI needs to be developed for this type of application.
The Mono for Android API Reference is at http://docs.mono-android.net/.
Tutorials (C# biased) can be found at http://mono-android.net/Tutorials
How-To documents at http://mono-android.net/Documentation
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.
SQLite SQL syntax is documented at http://www.sqlite.org/lang.html.
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 interesting topics in the future.
Brian Long has spent the last 1.5 decades as a trainer, trouble-shooter and mentor focusing on the Delphi, 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.
© 2011 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