We are writing the first application on Mono Android

Hello. In this article, I would like to share my experience in creating applications for the Android mobile platform using Mono and to take a simple example.

To get started with Mono Android you need to install:


Also, to create an xml layout (let's call it markup) we need one of the graphical tools. I use DroidDraw , but there are many alternatives on the net. So everyone can choose something to their taste.
After installing all of the above, you must create and configure one (or several) Android device emulators. You can also do this when you first start the application. In my example, I am using an emulator with Android version 2.1.1.
Now you can create our first Mono Android project.

The first Mono Android project


Create a new project


And call it MyFirstMonoAndroidApplication.


The new project contains several elements: Assets and Resources directories and a class called Activity1.
Assets in this example will not be affected. I would like to dwell on the remaining elements in a little more detail.
With resources, everything is quite simple. The Drawable directory stores the images used in the application. The Layout directory contains a set of xml layouts. And in the Values ​​directory are stored various predefined string values ​​that we use in our application.
All resources used in the application should be marked in the properties as AndroidResource.
Let's move on to our Activity1 class. As you can see, it inherits from the base class Activity. What is an activity? Activity is one specific task that a user can perform. Almost all Activity interact with the user through a graphical interface (xml markup).

Pay attention to the line SetContentView (Resource.Layout.Main);
It is in this place that the markup is loaded and set up for the current Activity.
Slightly change the markup and code of the Activity itself.
Let it be a simple form with two buttons, each of which handles the execution of another Activity.

Markup:

android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
     android:id="@+id/FirstExample"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="First Example">
  android:id="@+id/SecondExample"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:text="Second Example">


* This source code was highlighted with Source Code Highlighter.


The main class of the application. This is what we will see at startup.
[Activity(Label = "My first mono android activity", MainLauncher = true, Icon = "@drawable/icon")]
 public class MyMainActivity : Activity
 {
  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);
   SetContentView(Resource.Layout.Main);
   Button firstExample = FindViewById


The code is quite simple and straightforward, except for using the new Intent class.
What is Intent? This is an abstract description of the operation being performed. In other words, it is the user's intention to do something specific. In our case, when you click on the button, the user will switch to another Activity.
To compile the code, you need to add the classes that we reference. Through the context menu of the project, add two new Activities with the names TitlesListActivity and MoreFriendlyRssFeedActivity.

I would like to demonstrate some simple examples that can help you learn Mono Android. One of the main things any programmer faces is listing.
Let it be a list of headlines from an RSS feed. Let's create a simple class for reading RSS.
public class RssReader
  {
    private const string _title = "title";
    private const string _link = "link";
    private const string _item = "item";
    private const string _channel = "channel";

    private static Func GetTitlesAndLinksFunc = (x => new RssListItem { Title = x.Element(_title).Value, Link = x.Element(_link).Value });

    public static IList GetRssListItems(params string[] rssUris)
    {
      List fullList = new List();

      IEnumerable itemsFromConcreteIteration;
      foreach (string rssUri in rssUris)
      {
        itemsFromConcreteIteration = GetRssFeedChannel(rssUri).Elements(_item);
        fullList.AddRange(itemsFromConcreteIteration.Select(GetTitlesAndLinksFunc));
      }

      return fullList;
    }

    public static IEnumerable GetTitles(string rssUri)
    {
      IEnumerable items = GetRssFeedChannel(rssUri).Elements(_item);
      return items.Select(x => x.Element(_title).Value);
    }

    public static XElement GetRssFeedChannel(string rssUri)
    {
      XElement feed = XElement.Load(rssUri);
      return feed.Element(_channel);
    }
  }

  public class RssListItem
  {
    public string Title { get; set; }
    public string Link { get; set; }
  }

* This source code was highlighted with Source Code Highlighter.


Now display this list in an Activity named TitlesListActivity.
To do this, we will use ListActivity, whose main (and only) purpose is to display the list.
Note that it does not need to specify xml markup and call SetContentView.

  [Activity(Label = "List")]
  public class TitlesListActivity : ListActivity
  {
    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);
      
      var titles = RssReader.GetTitles("http://habrahabr.ru/rss/blogs/mono/");
      ListAdapter = new ArrayAdapter(this, Android.Resource.Layout.SimpleListItem1, titles.ToArray());
    }
  }

* This source code was highlighted with Source Code Highlighter.


Of particular interest is the following resource: Android.Resource.Layout.SimpleListItem1. This is one of the predefined resources, the full list of which (along with the markup) can be found here .

Its markup:
  android:id="@android:id/text1"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:textAppearance="?android:attr/textAppearanceLarge"
  android:gravity="center_vertical"
  android:paddingLeft="6dip"
  android:minHeight="?android:attr/listPreferredItemHeight"
/>

* This source code was highlighted with Source Code Highlighter.


It's time to launch our application.


Clicking on the first button opens a new Activity with a list of headers displayed in the RSS feed.

Excellent! Everything works, but, of course, I want something more complicated.

Let's complicate the task


Add the ability to select a specific RSS feed from the list and open a post from the feed in the browser.
To get started, let's work a bit with resources: add two images with the Mono and .NET logos in the Drawable directory (do not forget to specify the type of resource!). Also in the Strings.xml file (Values ​​directory) add an array of values ​​for the drop-down list:

  
  MyFirstMonoAndroidApplication
  
    Mono
    .Net
    Mono and .Net
  



* This source code was highlighted with Source Code Highlighter.


Now you need to create a new markup MoreFriendlyRssFeed.xml

android:layout_width="fill_parent"
android:layout_height="fill_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical">
     android:id="@+id/FrameworkSelector"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  
     android:id="@+id/RssEntries"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content">
  


* This source code was highlighted with Source Code Highlighter.


It's very simple: Spinner to select a ribbon and ListView to display a list. It is important to understand that at this stage, he does not know anything about marking up the elements inside the ListView (or rather, its adapter). Based on this markup, we can say that ListView simply displays a "some" list.

You also need to create markup for the list item. Let's call it RssRow.xml. Let each element of the list include a button with an image and text - the title of the article.

  android:layout_width="fill_parent"
  android:layout_height="wrap_content"
  android:padding="6dip">
     android:id="@+id/LogoButton"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  android:src="@drawable/mono">
  
     android:id="@+id/Title"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content">
  


* This source code was highlighted with Source Code Highlighter.


It is time to move on to the most important thing: the implementation of the Activity, which will link all our parts together.
 [Activity(Label = "Friendly List")]
 public class MoreFriendlyRssFeedActivity : Activity
 {
  protected override void OnCreate(Bundle bundle)
  {
   base.OnCreate(bundle);
   SetContentView(Resource.Layout.MoreFriendlyRssFeed);

   Spinner spinner = FindViewById(Resource.Id.FrameworkSelector);
   spinner.ItemSelected += spinner_ItemSelected;
   ArrayAdapter adapter = ArrayAdapter.CreateFromResource(this, Resource.Array.frameworks, Android.Resource.Layout.SimpleSpinnerItem);
   adapter.SetDropDownViewResource(
Android.Resource.Layout.SimpleSpinnerDropDownItem);
   spinner.Adapter = adapter;
  }

  void spinner_ItemSelected(object sender, ItemEventArgs e)
  {}
 }

* This source code was highlighted with Source Code Highlighter.


Let's pay attention to one more predefined resource Android.Resource.Layout.SimpleSpinnerItem. For convenience, I will also give its markup:
android:id="@android:id/text1"
style="?android:attr/spinnerItemStyle"
android:singleLine="true"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />

* This source code was highlighted with Source Code Highlighter.


To display the text in the list, use the ArrayAdapter class. If we need to display something more complex, then we are faced with the need to implement our own class, an inheritor from ArrayAdapter, which overrides the GetView method. Create an RssListItemAdapter class to bind and display data:
public class RssListItemAdapter: ArrayAdapter
  {
    private IList Items;

    public RssListItemAdapter(Context context, int textViewResourceId, IList items)
      : base(context, textViewResourceId, items)
    {
      Items = items;
    }

    public override View GetView(int position, View convertView, ViewGroup parent)
    {
      View view = convertView;
      if (view == null)
      {
        LayoutInflater inflater = (LayoutInflater)Context.GetSystemService(Context.LayoutInflaterService);
        //выбираем разметку, которую будем наполнять данными.
        view = inflater.Inflate(Resource.Layout.RssRow, null);
      }

      //получаем текущий элемент
      RssListItem item = Items[position];

      //находим и привязываем к данным содержимое одного элемента в списке
      //пусть при нажатии на кнопку открывается браузер с соответствующей статьей
      ImageButton btnLogo = (ImageButton)view.FindViewById(Resource.Id.LogoButton);
      btnLogo.Click += delegate
                 {
                   Intent browserIntent = new Intent("android.intent.action.VIEW", Android.Net.Uri.Parse(item.Link));
                   Context.StartActivity(browserIntent);
                 };
      
      //добавляем картинку на кнопку (из ресурсов)
      btnLogo.SetImageResource(item.Title.StartsWith("Mono") ? Resource.Drawable.mono : Resource.Drawable.net);
      
      //устанавливаем текст
      TextView txtTitle = (TextView)view.FindViewById(Resource.Id.Title);      
      txtTitle.Text = item.Title;

      //возвращаем элемент списка с привязанными данными
      return view;
    }
  }

* This source code was highlighted with Source Code Highlighter.


Now it is possible to bind data to the list and display it in the form we need. We add the ability to bind to data in the event handler for selecting an item from the list.
    void spinner_ItemSelected(object sender, ItemEventArgs e)
    {
      ListView view = FindViewById(Resource.Id.RssEntries);      

      switch (e.Position)
      {
        case 0:
          view.Adapter = new RssListItemAdapter(this, Resource.Layout.RssRow, RssReader.GetRssListItems("http://habrahabr.ru/rss/blogs/mono/"));
          break;
        case 1:
          view.Adapter = new RssListItemAdapter(this, Resource.Layout.RssRow, RssReader.GetRssListItems("http://habrahabr.ru/rss/blogs/net/"));
          break;
        case 2:
          view.Adapter = new RssListItemAdapter(this, Resource.Layout.RssRow, RssReader.GetRssListItems("http://habrahabr.ru/rss/blogs/mono/", "http://habrahabr.ru/rss/blogs/net/"));
          break;
      }
    }

* This source code was highlighted with Source Code Highlighter.


Run the application and open the second example. Now we have the ability to select RSS feeds (or a set of feeds).


Our list will look as follows:


When you click on the button next to the heading, the corresponding article will open in the browser.


Running an application on an Android device


The point is small: run the application on a specific Android device. If we try to do this right now, we will get an error when trying to build the apk (Android Package) file. I would also like to indicate that the trial version of Mono Android allows you to run applications only on the emulator. Fortunately, my version is no longer trial, so I can bring the example to its logical conclusion.
For the correct assembly of the installation package, you must create AndroidManifest.xml. This file contains key information about the application, information without which launching the application on the device is impossible.

There is the possibility of creating AndroidManifest.xml through the project properties:


But it will be much more interesting to write it with your hands:


  
  

  
  


* This source code was highlighted with Source Code Highlighter.


Now you can collect the apk file. Build -> Package MyFirstMonoAndroidApplication for Android (.apk)
Copy it to your Android device and launch it. During installation, a warning is displayed:
Allow this application to: Full access to Internet.
That is, all the necessary requirements from the manifest will be shown to the user before installation. We confirm, we are waiting for the installation to complete. And ...


Thank you for your attention.

Link to the application source code

Also popular now: