One of the major reasons for using Xamarin.Android is the use of C# as the programming language. But this is not the only benefit as that same C# code can be shared with other platforms, such as iOS, Windows, or Mac OS.
First, we are going to create the project structure that we are going to use to create our cross-platform app. In this example, we will only target Xamarin.Android and the Console, but extra platforms can be added.
XamarinCodeSharing
.XamarinCodeSharing.Droid
XamarinCodeSharing.Desktop
XamarinCodeSharing.Core
XamarinCodeSharing.Core
. If you are using Xamarin Studio, navigate to Build | General. Or if you are using Visual Studio, navigate to Library and then click on Change under the Targeting section.NuGet
package, Microsoft.Net.Http
, which simplifies the process of using HTTP and REST services. Install this package into each of the three projects.XamarinCodeSharing.Droid
to XamarinCodeSharing.Core
and a project reference from XamarinCodeSharing.Desktop
to XamarinCodeSharing.Core
.XamarinCodeSharing.Core
project.MyClass.cs
, and Visual Studio created a file named Class1.cs
.BlogItem
, which will represent the actual blog entries. This bit is very simple and is just a set of properties:using System; namespace XamarinCodeSharing.Core { public class BlogItem { public string Title { get; set; } public string Link { get; set; } public DateTime PublishDate { get; set; } public string Description { get; set; } } }
XamarinBlog
, which both represents the blog as well as provides a means to download the blog:using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net.Http; using System.Threading.Tasks; using System.Xml.Linq; using System.Net; namespace XamarinCodeSharing.Core { public class XamarinBlog { private const string BlogUrl = "http://blog.xamarin.com/feed"; // blog metadata properties public string Title { get; set; } public string Link { get; set; } public List<BlogItem> Items { get; private set; } // Download the feed, parse it and return a blog object public static async Task<XamarinBlog> Download() { HttpClient client = new HttpClient(); HttpResponseMessage response = await client.GetAsync(BlogUrl); // if all went well, read the feed, otherwise fail if(response.IsSuccessStatusCode) { return await ParseResponse(response.Content); } else { throw new Exception("There was a problem."); } } // Read the response out of the content and // create objects private static async Task<XamarinBlog>ParseResponse( HttpContent content) { XamarinBlog blog = new XamarinBlog(); using(Stream stream = await content.ReadAsStreamAsync()) { XDocument doc = XDocument.Load(stream); XElement channel = doc.Root.Element("channel"); // load the blog metadata out of the xml blog.Title = WebUtility.HtmlDecode( channel.Element("title").Value); blog.Link = WebUtility.HtmlDecode( channel.Element("link").Value); // load the blog items out of the xml var items = from item in channel.Elements("item") select new BlogItem { Title = WebUtility.HtmlDecode( item.Element("title").Value), Link = WebUtility.HtmlDecode( item.Element("link").Value), PublishDate = DateTime.Parse( WebUtility.HtmlDecode( item.Element("pubDate").Value)), Description = WebUtility.HtmlDecode( item.Element("description").Value), }; blog.Items = items.ToList(); } return blog; } } }
There are several important points to note here. We are using the async
and await
keywords to make asynchronous code easier to read, something which is not available in Java. Another feature is LINQ to XML to make working with XML easier to parse, another feature not available to Java. And finally, WebUtility.HtmlDecode
is used as all the data is HTML encoded inside the XML.
Now that we have created the main logic of the app, we can look at those native implementations. First, we will create the Console app that will run on almost any desktop operating system, such as Windows, Mac OS, and most of the flavors of Linux:
Program.cs
file with the following:using System; using XamarinCodeSharing.Core; using System.Threading.Tasks; namespace XamarinCodeSharing.Desktop { class MainClass { public static void Main(string[] args) { GetBlogItems().Wait(); Console.WriteLine("Press any key to quit."); Console.ReadKey(); } private static async Task GetBlogItems() { Console.WriteLine("Downloading blog..."); XamarinBlog blog = await XamarinBlog.Download(); Console.WriteLine("Download finished."); Console.WriteLine(); Console.WriteLine("{0} ({1} items)", blog.Title, blog.Items.Count); foreach (var item in blog.Items) { Console.WriteLine(item.Title); Console.WriteLine( item.PublishDate.ToString("d MMMM yyyy")); Console.WriteLine(item.Description); Console.WriteLine(); } } } }
If we run the desktop project now, the console will start up, download the blog feed, and then display each entry along with a short summary. Last but not least, we want to get that mobile version going. And what better platform to support first than Android?
MainActivity.cs
file with the following:using System.Collections.Generic; using System.Linq; using Android.App; using Android.OS; using Android.Runtime; using Android.Widget; using XamarinCodeSharing.Core; namespace XamarinCodeSharing.Droid { [Activity( Label = "XamarinCodeSharing.Droid", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : ListActivity { private const string TitleKey = "title"; private const string SubtitleKey = "subtitle"; protected async override void OnCreate(Bundle bundle) { base.OnCreate(bundle); var progress = new ProgressDialog(this); progress.SetTitle("Downloading blog..."); progress.SetMessage( "Please wait while we download the Xamarin blog..."); progress.Show(); XamarinBlog blog = await XamarinBlog.Download(); var items = from item in blog.Items select new JavaDictionary<string, object> { { TitleKey, item.Title }, { SubtitleKey, item.Description } }; ListAdapter = new SimpleAdapter( this, items.Cast<IDictionary<string, object>>().ToList(), Android.Resource.Layout.SimpleListItem2, new []{ TitleKey, SubtitleKey }, new []{ Android.Resource.Id.Text1, Android.Resource.Id.Text2 }); progress.Dismiss(); progress.Dispose(); } } }
If we run this Android app now, we shall get that app that downloads the latest Xamarin blog posts and displays them in a neat list.
Portable class libraries is one of the most important aspects of code reuse. Although there are many different ways to reuse code, such as file linking or shared projects, none can match the reliability and ease of simply reusing the compiled assembly. This assembly can be tested and verified and then used and reused without fear of problems arising on different platforms.
Why? It is because each platform in each portable class library profile promises to support all the features, for all platforms, in that profile, and all those features function exactly the same.
Using Xamarin.Android, we now have all the features of the .NET runtime available, the same runtime that runs on almost all devices. Along with that same runtime, we can now build libraries that run on that runtime, and those libraries will run on all platforms that have the same runtime. Those platforms include iOS, Android, Windows Phone, Mac OS, Windows, Linux, and even more, such as PlayStation!
Although we can never achieve 100 percent code reuse, as each platform has differences (especially in the user interface), much of the code lives below the surface and can be reused. And using the commonality of the runtime and languages, we can create abstractions that can work around the platform differences, resulting in even more code reuse.
Although we only covered two platforms in this example, we can already see that it takes more code to work with the data than it does to display it. Adding extra platforms, such as Windows Phone and iOS, will result in this ultra-simple example app being able to support the major mobile operating systems, with the only difference being the UI.