Mono for Android

Using C# to Develop for Android Devices

Brian Long Consultancy & Training Services Ltd.
Jan 2012

Page selection: Previous  Next

Android architecture overview

To get an understanding of how a simple Android applications works we’ll take a generalised overview of its architecture.

Application building blocks

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:

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.

Android manifest

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.

Application lifecycle

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.

Application resources

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:

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.

Alternative resources

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.

UI layout files

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 at some point in the future.

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.

Conclusion

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.

Technical Resources

The Mono for Android API Reference is at http://docs.xamarin.com/android/api.

Tutorials can be found at http://docs.xamarin.com/android/tutorials

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.

Comments

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.

About the author

Brian Long has spent the last 1.6 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.

© 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

Previous page

Next page