Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / Xamarin

Introduction to Xamarin.Android

4.92/5 (33 votes)
25 Aug 2014CPOL14 min read 114.6K   11  
Introduction to Xamarin.Android

Introduction

This article gives an overview of Xamarin.Android, which is a MonoDroid plug-in for Visual Studio. It allows .NET developers to build applications that target the Android platform using their existing IDE and language, therefore without having to learn Java / Eclipse. The article will go through the basics of creating a Xamarin.Android project as well explaining the key elements and project structure.

Background

Xamarin are a California based software company who created Mono, MonoTouch and Mono for Android which are all cross-platform implementations of the Common Language Infrastructure (CLI) and Common Language Specifications (which are often referred to as Microsoft.NET)

Extracted from Visual Studio Magazine

"Monodroid is a plug-in to Visual Studio 2010. This plug-in allows developers to deploy apps to the Android Emulator running locally, as well as to a physical device connected over a USB cable and Wi-Fi. The plug-in allows MonoDroid to actively work with the rest of the Visual Studio ecosystem and integrate with the tools that developers are already using."

Using the C# language, developers are able to build native apps that can target iOS, Android and Windows Phone. They can use either Xamarin Studio (which is an IDE that is downloaded as part of the Xamarin.Android SDK) or they can use Visual Studio. Personally, I use Visual Studio as that is what I am most familiar with. For the purposes of this article, I will use Visual Studio.

This article assumes the reader is familiar with C#, Visual Studio and the .NET Framework. It also assumes that you have downloaded the Xamarin.Android SDK from the Xamarin web site. if you haven't then download it now.

Creating your First Xamarin.Android Project

To create your first Xamarin.Android project, open Visual Studio and select File -> New -> Project. In the list of installed templates on the left, select Visual C#. Underneath this, you should see Android. When selecting this, you should see a list of Xamarin.Android project templates similar to those shown in the screenshot below.

visual studio android template projects

As you can see, there are several installed Xamarin.Android project templates. For the purposes of this article, I will use the Android Application template. Give your project a meaningful name (I have named mine MyDemo but feel free to name yours whatever you like). Click OK to continue to create your project.

Project Structure

When your project has been created, you will see the following project structure.

visual studio android template projects

Expand the Resources folder and its sub-folders as in the screenshot below:

visual studio android template projects

Let's go through the various parts of the project one at a time and explain what they are and what they do. I won't go into the standard .NET elements, but instead focus on those that are specific to Xamarin.Android.

Activity1.cs - This is the default Android Activity that is created. An Activity is an Android specific entity. They define a single, focused thing that the user can perform such as adding a new customer, viewing a list of goods and so on. They have their own lifecycle and events. They are key to an Android application and so it is important to understand them.

Expand the Properties folder.

  • AndroidManifest.xml - This file defines essential information about the application to the Android system. Every Android application has one of these. This file MUST be present for the application to run as it defines such things as the name of the application to the Android system, describes the components of the application, declares permissions and defines the minimum Android API level for example.

Expand the Resources folder.

  • Drawable - This folder contains the images for your application. If your application requires different sized images for the different screen sizes, then create a sub-folder underneath here for each of the different resolutions.
  • Layout - This folder contains the Android layout (.AXML) files for your project. An Android layout file is similar to an HTML or ASPX file. It defines a single Android screen using XML syntax. Create a new layout for each screen. If your application requires different layouts for landscape or portrait, then you need to create layout-land and layout-port sub-folders respectively. By default, there is a layout created automatically for you called Main.axml. This is the UI layout that is invoked by the default Activity class mentioned earlier - Activity1.cs.
  • Values - This folder contains resource definitions that your application uses such as string values. For example, you could store the name of the application or dropdown list items in the Strings.xml file
  • Resource.Designer.cs - This file contains the class definitions for the generated IDs contained within the application. This allows application resources to be retrieved by name so the developer does not have to use the ID. The file therefore maps the application resource name to its generated ID. The file is updated each time the project is built. This file should NOT be updated by the developer.

Other files you could have underneath the Values folder include:

  • Arrays.xml
  • Colors.xml
  • Dimensions.xml
  • Styles.xml

The default entries for Strings.xml are listed below:

XML
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="Hello">Hello World, Click Me!</string>
    <string name="ApplicationName">MyDemo</string>
</resources>

To use a Strings.xml entry from an Android layout (.AXML) file.

XML
<TextView
        android:text="@string/ApplicationName"
        android:id="@+id/txtApplicationName" />

To use a Strings.xml entry from your application code.

C#
string applicationName = GetString(Resource.String.ApplicationName);

An example entry for Arrays.xml:

XML
<?xml version="1.0" encoding="utf-8" ?>
<resources>
  <string-array name="payment_types">
    <item>Cash</item>
    <item>Debit Card</item>
    <item>Credit Card</item>
    <item>Cheque</item>
  </string-array>
</resources>

You can then use the payment_types array list in code as follows:

C#
string[] paymentTypes = Resources.GetStringArray(Resource.Array.payment_types);

Other folders you could add to your project structure as your application grows in complexity could include:

  • Fragments
  • Adapters

The Activity Class

It's worth spending a little time going through the Android Activity class in a little more detail as they are fundamental to building Xamarin.Android applications.

As already mentioned, an Activity defines a single, focused thing that the user can perform. Typically, an Activity will launch an Android layout (or screen). The user interacts with a layout (.AXML) file, but the functionality is defined within the Activity.

Essentially an Activity has four states.

  • If an Activity is in the foreground, then it is active or running. Only one Activity can be running at a time. Android holds all open Activities in a stack structure where they can be popped or pushed as necessary.
  • If an Activity has lost focus but remains visible, then it is said to be paused.
  • An Activity that has been paused can be killed in scenarios such as low memory where Android needs to free up resources.
  • If an Activity is completely obscured by another Activity, then it is said to be stopped.
  • If an Activity is paused or stopped, then the Android system can remove the Activity from memory. It can do this by requesting that the Activity finishes, or it can simply kill the Activity. When the Activity is displayed again to the user, it needs to be restarted and restored to its previous state.

The following diagram (extracted from Android Developers) shows the lifecycle of an Activity.

activity lifecycle

Here is the code from the default Activity Activity1.cs.

C#
using System;

using Android.App;
using Android.Content;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Android.OS;

namespace MyDemo
{
    [Activity(Label = "MyDemo", MainLauncher = true, Icon = "@drawable/icon")]
    public class Activity1 : Activity
    {
        int count = 1;

        protected override void OnCreate(Bundle bundle)
        {
            base.OnCreate(bundle);

            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.Main);

            // Get our button from the layout resource,
            // and attach an event to it
            Button button = FindViewById<Button>(Resource.Id.MyButton);

            button.Click += delegate { button.Text = string.Format("{0} clicks!", count++); };
        }
    }
}

Note how the Activity sets the layout (or screen) to use. It does this by invoking the function SetContentView(). Note how the layout name is passed as an argument to the function rather than its ID. The resource definition for the Main layout is contained in the file Resource.Designer.cs that was mentioned earlier. This file maps the name of the layout (which in this case is called Main) to its ID. The ID will be a unique integer value.

Note how the generated ID for the Button UI element is determined using the Android function FindViewById(). All Android UI elements have an associated ID. This ID is defined in the file Resource.Designer.cs.

Resources

We have briefly mentioned the file Resource.Designer.cs and how it maps the name of a resource to its generated ID.

When you create layouts in Android, you will add Views (a View is an Android term to refer to any UI element such as buttons, textboxes, checkboxes, etc.). You will give these UI elements a meaningful name (btnAddNewCustomer, txtCustomerSurname for example). When you need to refer to these UI elements in your application code, you determine its name via its generated ID.

The following code snippet shows the class definitions for the Id and Layout classes. Each ID is defined as a const int. This shows clearly how a UI element (layout, button, etc.) is mapped to its generated ID. Whenever you add / delete UI elements to your layouts or add / delete layouts themselves, the Resource.Designer.cs file is automatically updated when you compile the application. So there is no need to manually edit this file!

C#
namespace MyDemo
{
    public partial class Resource
    {
        public partial class Id
        {
            // aapt resource value: 0x7f050000
            public const int MyButton = 2131034112;

            private Id()
            {
            }
        }

        public partial class Layout
        {
            // aapt resource value: 0x7f030000
            public const int Main = 2130903040;

            private Layout()
            {
            }
        }
    }
}

The Fragment Class

The Fragment class is another important Android element to understand when building a Xamarin.Android application. They represent a portion of the user interface in an Activity. You can think of a Fragment as a modular section of an Activity. They have their own lifecycle and events similar to an Activity. An Activity may be associated with zero or more Fragments.

In common with an Activity a Fragment can receive its own input events. You can add / remove a Fragment from an Activity or even from another Fragment at runtime. A Fragment can be added dynamically to different Activities and Fragments and therefore enable reusability.

The following diagram (extracted from Android Developers) shows the lifecycle of a Fragment.

activity lifecycle

In the following code snippet, clicking on the Notepad button invokes the Notepad Fragment (which is a screen for allowing users to enter notes into the application).

C#
public class MyActivity : Activity
{
    protected override void OnCreate(Bundle bundle)
    {
        var notePadButton = FindViewById<Button>(Resource.Id.btnNotepad);

        notePadButton.Click += (o, e) =>
                                       {
                                           var ft1 = FragmentManager.BeginTransaction();
                                           var current = FragmentManager.FindFragmentById(Resource.Id.layoutFrame);
                                           ft1.Remove(current);
                                           ft1.Add(Frame, new Notepad());
                                           ft1.Commit();
                                       };
    }
}

The same code could be used to launch the Notepad Fragment from any other part of the application, whether it was from an Activity or from another Fragment. Fragments enable reusability of functionality.

The Intent Class

An Intent is a messaging object that can be used to represent an action from another component. There are three fundamental uses for an Intent.

  • To start an Activity
  • To start a Service
  • To start a Broadcast

In the following example, the Admin page Activity contains a button for launching the user group Activity screen which is responsible for assigning a user to a user group. This is achieved by using an Intent.

C#
public class AdminPage : Activity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);
        SetContentView(Resource.Layout.AdminScreen);

        var assignUserButton = FindViewById<Button>(Resource.Id.btnAssignUser);
        assignUserButton.Click += (o, e) =>
        {
            var intent = new Intent(this, typeof(UserGroupActivity));
            StartActivity(intent);
            Finish();
        };
    }
}

The Application Class

If you need to maintain state across your application, then you will need an Application class. Although it is possible to pass information to / from Activity and Fragment classes, if you have a requirement to maintain global state (such as the currently logged in user name), then you achieve this using an Application class.

C#
[Application]
public class MyApplication : Application
{
    public string CurrentUser = "";
}

Note that the class is decorated with the [Application] attribute. This is so that the necessary element is generated and added to the AndroidManifest.xml file. This ensures the class is instantiated when the application / package is created.

XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
android:installLocation="auto" package="com.mydemo.apk" android:versionCode="1">
    <!--This line ensures the application class is instantiated automatically-->
    <application android:label="MyDemo" android:icon="@drawable/Icon"></application>
</manifest>

To use the Application class in your own code, you will also need to determine the current Context. In Android, the Context refers to the current state of the application / object. The Context class is also the base class for (but not limited to)

  • Activity class
  • Service class

There are several ways in which you can determine the application Context. One way is to add a method to your Application class definition that returns the Context as in the following code:

C#
[Application]
public class MyApplication : Application
{
    public Context GetContext()
    {
        return ((this).ApplicationContext);
    }
}

Then in your application code, you can invoke it as follows.

C#
MyApplication application = (MyApplication)GetContext();
String username = application.GetCurrentUser();
String password = application.GetPassword();

The Android Manifest

Your Xamarin.Android application will fail to run without this file. It defines important information about your application to the Android system and it MUST be called AndroidManifest.xml. No other name can be used. It is broadly similar to a web application's web.config file.

The manifest file defines essential information including (but not limited to):

  • The name of the application
  • Describes the components of the application
  • Declares permissions
  • Defines the minimum Android API level

The diagram below shows the basic structure of the manifest file and the various elements it can contain.

XML
<!--?xml version="1.0" encoding="utf-8"?-->
<manifest>

    <uses-permission />
    <permission />
    <permission-tree />
    <permission-group />
    <instrumentation />
    <uses-sdk />
    <uses-configuration />  
    <uses-feature />  
    <supports-screens />  
    <compatible-screens />  
    <supports-gl-texture />  

    <application>

        <activity>
            <intent-filter>
                <action />
                <category />
                <data />
            </intent-filter>
            <meta-data />
        </activity>

        <activity-alias>
            <intent-filter> . . . </intent-filter>
            <meta-data />
        </activity-alias>

        <service>
            <intent-filter> . . . </intent-filter>
            <meta-data/>
        </service>

        <receiver>
            <intent-filter> . . . </intent-filter>
            <meta-data />
        </receiver>

        <provider>
            <grant-uri-permission />
            <meta-data />
            <path-permission />
        </provider>

        <uses-library />

    </application>

</manifest>

Below is an example of an AndroidManifest.xml file.

XML
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" 
android:installLocation="internalOnly" android:icon="@drawable/mydemo" 
package="com.mydemo.app" android:versionCode="13" android:versionName="0">
    <uses-sdk android:targetSdkVersion="15" android:minSdkVersion="15" />
    <application android:label="MyDemo" 
    android:theme="@android:style/Theme.Holo.NoActionBar.Fullscreen" 
    android:icon="@drawable/mydemo"></application>
    <service android:enabled="true" android:name=".BackgroundService" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.BATTERY_STATS" />
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <uses-permission android:name="android.permission.CAMERA" />
    <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
    <uses-permission android:name="android.permission.CONTROL_LOCATION_UPDATES" />
    <uses-permission android:name="android.permission.DEVICE_POWER" />
    <uses-permission android:name="android.permission.FLASHLIGHT" />
    <uses-permission android:name="android.permission.FORCE_BACK" />
    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
    <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
    <uses-permission android:name="android.permission.READ_CALENDAR" />
    <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.READ_INPUT_STATE" />
    <uses-permission android:name="android.permission.READ_LOGS" />
    <uses-permission android:name="android.permission.READ_OWNER_DATA" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.SET_ALARM" />
    <uses-permission android:name="android.permission.RECORD_AUDIO" />
    <uses-permission android:name="android.permission.SET_ORIENTATION" />
    <uses-permission android:name="android.permission.SET_TIME" />
    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
    <uses-permission android:name="android.permission.STATUS_BAR" />
    <uses-permission android:name="android.permission.UPDATE_DEVICE_STATS" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_CALENDAR" />
    <uses-permission android:name="android.permission.WRITE_CONTACTS" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_OWNER_DATA" />
    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
    <uses-permission android:name="android.permission.WRITE_SETTINGS" />
</manifest>

Designing and Architecting Your Application

The topic of designing and architecting a Xamarin.Android application is worthy of an article of its own, so I won't go into vast amounts of detail. Since it is more difficult to retro-fit design elements into your application afterwards, it is worth getting these firmly in place from the outset.

There are no hard and fast rules as to how you design and architect your Xamarin.Android application, but there are guidelines that you may want to consider.

Firstly, I would create subclasses of the key Android classes, i.e., ActivityBase, FragmentBase, AdapterBase and so on. Then populate these classes with the generic behaviour that is required. When creating a new Android class, ensure it inherits from your own derived version of the class. This enables reusability and leads to easier maintenance as you can change base behaviour in one place.

It is worthwhile ensuring your application is loosely coupled and that there are clear separation of concerns between the various parts of the application. An n-tier architecture is therefore worth exploring.

  • User-interface layer
  • Business rules layer
  • Data layer

In the following example, the login button invokes a method of the Activity which in turn calls a business rule to determine if the user's credentials are correct. It doesn't matter if the function invokes a web service or a data layer function (which in turn looks up the user in the local database). The important point is that there is a clear separation of concerns between the various parts of the application. The actual details of how the application is architected is for the developer to decide.

C#
public class LoginPage : Activity
{
    protected override void OnCreate(Bundle bundle)
    {
        base.OnCreate(bundle);

        var userNameText = FindViewById<EditText>(Resource.Id.txtUserName);
        var passwordText = FindViewById<EditText>(Resource.Id.txtPassword);
        var loginButton = FindViewById<Button>(Resource.Id.btnLogin);
        loginButton.Click += (o, e) => PressLoginButton(userNameText.Text, passwordText.Text);
    }

    private void PressLoginButton(string username, string password)
    {
        return BizRules.IsUserAuthenticated(username, password);
    }

There doesn't seem to be any agreement as to whether an Android application is a good fit for the MVC design pattern. The arguments against its use include the fact that the Activity serves as both the View and the Controller and that an Activity has its own events and lifecycle that don't fit with MVC. I'm not going to go into this in any detail except to make you aware of the lack of any general agreement on the subject, and that if you wish to implement MVC, then you are free to investigate the matter further.

Unit-testing Your Application

If you are considering unit-testing your application, then you will need to architect your application in a way that supports this. You will need to make these changes from the very outset as attempting to retro-fit them afterwards will entail significant effort. Also, if you are considering targeting other mobile platforms in the future (iOS, Windows Phone), then architecting them with unit-testing in mind will ensure that this is achievable.

NUnit does not work with Xamarin.Android nor do any other unit-testing frameworks. The intent of Monodroid and Monotouch is to provide a .NET development environment that allows you to easily port business logic between different environments. As a result, you can't really test Android / iOS specific code, but you can test generic .NET business logic code. In the Monodroid projects that I write, I create three projects in the solution. One is the Android project, another is a .NET project that holds all of my non-Android business logic and the final project is an NUnit test project which tests the functionality in the aforementioned .NET business logic project. Monodroid project files cannot be tested, but .NET code files linked into Monodroid projects can be tested with whatever unit-testing framework you choose.

Your solution should therefore contain the following three projects:

  • A project which contains the Xamarin.Android specific functionality and which has been created from a Xamarin.Android project template
  • A project which contains your business logic (you can add another project for your data layer if necessary)
  • A project containing your unit tests

The key therefore to unit-testing your Xamarin.Android application is to keep all your Xamarin.Android code in a separate project. So out of the three projects in the solution described above, only one would be a Xamarin.Android project. It is by creating your solution in this way that you will be able to target other mobile platforms as you can reuse your business logic and test projects.

Summary

Hopefully, this article has given you sufficient information for you to start creating your own Xamarin.Android applications. Feel free to leave a comment if you would like me to further elaborate on anything within this article.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)