Mike Taulty's Blog
Bits and Bytes from Microsoft UK
Baby Steps on Android with Xamarin–Part 4

Blogs

Mike Taulty's Blog

Elsewhere

Archives

Following up on previous posts;

Baby Steps with Xamarin on Android - Part 1

Baby Steps on Android with Xamarin–Part 2

Baby Steps with Xamarin–Part 3

which I now realise have very variable titles – the time has come to pitch in and try and get my very limited “app” functionality moved across from Windows/Phone to Android.

In doing that I want to take an approach of not changing any of my portable code – the code that I’ve built into the library I created called CrossPlatform. I want to leave that code entirely alone even if that means more work on Android. I’ll live with that in the interests of trying to keep what I’ve already got intact.

I’m also pretty conscious that my portable code is skewed towards the way that I work on Windows/Phone – i.e. ViewModels with bindable properties and commands – and that these constructs are probably not the natural way of working on Android without some MVVM framework to help out. Regardless, I’ll try and code my way around it.

I figured that I would leave the Activity1 class that the template had inserted into the project for me but rename it to SearchPageActivity and then scrub the UI apart from the LinearLayout that’s present in the Main.axml file (which I also renamed to SearchPage.axml).

Working on the SearchPage Activity/Page

The first thing that I was trying to do was get the backdrop image set on my page. It took me longer than the 20 seconds I was expecting Smile in that I was surprised that using the AXML andriod : background attribute didn’t require a .png extension on my file and also that the resources folder in the project structure was named Drawable rather than lower-case drawable although, to be fair, the tooling warned me about this so that was easy enough to sort out.

I also had to keep remembering to set items such that their build action was AndroidResource but that’s easy enough.

I quite like the way in which resources seem to be referred to but it felt a bit inconsistent. For instance, I can understand why this resource;

image

is referred to from .axml by @drawable/backdrop but it’s a bit harder to figure out why a string in this resource;

image

is referred to from .axml by @string/SearchPageTitle. It’s nice once you know about it but I guess there’s some assumed association between the strings living in that xml file and the “@string” locator that wasn’t that obvious to me.

What I would say is that I like the code generation that’s done against all these resources. Windows Phone projects do a very similar thing to this in Visual Studio but Windows 8.1 apps don’t and I think generally, I like the way that the tooling here is generating me a Resource class with properties like Id, Layout, String hanging off it – it’s nice and clear and simple.

I managed to set an ImageButton to display an image which foxed me for a moment while I tried to figure out;

  1. That controls here like Button/ImageButton seem a bit less flexible than in XAML where you have the notion of a content control which can display arbitrary content. So, in XAML an “ImageButton” would make no sense because a Button can display an image (or anything else) as its content.
  2. How to specify pixel sizes as dp, px, sp values.
  3. How to think about layout and alignment – equivalents of Horizontal/VerticalAlignment in the XAML world. I don’t think I’ve quite got that figured out just yet.
  4. That a TextView is a TextBlock whereas an EditText is a TextBox.

but that didn’t take too long.

In my XAML apps, I’d used XAML in my app.xaml file in order to declare an instance of a Locator class that I had defined in my CrossPlatform library and which then surfaces ViewModels that my different views can bind to and which are built up with their dependent services via Autofac. This means that my Views never need to know anything much about where any of the implementation is happening.

I don’t know how to do that (or even whether I can) in my Android app and so I tried to go with a simpler route - to write a little class to present the Locator as a singleton for the app;

  static class ServiceLocation
  {
    static Locator locator;

    static ServiceLocation()
    {
      locator = new Locator();

      locator.Initialise(typeof(NavigationService),
        typeof(PhotoSavingService));
    }
    public static Locator Locator
    {
      get
      {
        return (locator);
      }
    }
  }

and, at this point I’ve written stubbed out implementations of the underlying services that the cross platform code needs – namely an INavigationService implementation and a IPhotoSavingService implementation and I’ve passed the types of those services through at construction time here which ultimately feeds those types down into the Autofac container.

That enabled me to get my first Activity and its “UI” up and on the screen and pushing the right bits into the underlying ViewModel. It’s a pretty simple thing so it’s not surprising that it’s not too difficult as there’s only a textbox and a button and then that textbox is “bound” to a property in the ViewModel and the clicking of the button is meant to be bound to an ICommand on the ViewModel and so the UI ended up looking 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"
    android:minWidth="25px"
    android:minHeight="25px"
    android:background="@drawable/backdrop">
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtSearch" />
    <Button
        android:layout_width="64dp"
        android:layout_height="64dp"
        android:id="@+id/btnSearch"
        android:background="@drawable/search" />
</LinearLayout>

and the code for the Activity ended up looking like this (note – I’m making no attempt to deal with the lifecycle of activities at the moment but, to be fair, my original Windows/Phone code didn’t bother to do that either although at least on those platforms I have slightly more a “clue” about where to implement that functionality and its implications whereas on Android I’m still a little in the dark);

  [Activity(Label = "flickrdemo.pages.search", MainLauncher = true, Icon = "@drawable/icon")]
  public class SearchPageActivity : Activity
  {
    SearchPageViewModel viewModel;

    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);
      
      this.SetContentView(Resource.Layout.SearchPage);

      // We pass the navigation service the Context that it's going to need
      // in order to create new activities. This is very similar to what 
      // we did on Windows/Phone except in those implementations we would
      // be passing a Frame object, not a Context object.
      ServiceLocation.Locator.Resolve<INavigationService>().RegisterFrame(
        this);

      this.viewModel = ServiceLocation.Locator.Resolve<SearchPageViewModel>();

      EditText txtSearch = this.FindViewById<EditText>(Resource.Id.txtSearch);
      ImageButton btnSearch = this.FindViewById<ImageButton>(Resource.Id.btnSearch);

      // Now begins the process of manual binding - could do an awful lot to
      // genericise this using a lot more reflection and so on but doing the
      // bare minimum right now.
      FakeBinding.ManualBindTextView(
        "SearchTerm", this.viewModel, txtSearch);

      FakeBinding.ManualBindImageButton(btnSearch, this.viewModel.SearchCommand);
    }
  }

You’ll note that I’m keeping around an instance of my SearchPageViewModel as a member of the class and that I resolve an instance of that type via the portable code library. I’m adding a class here in the Android project called FakeBinding which is attempting to wire up controls to ViewModels – I’ll add the code for that class to the post later on.

With that in place, I had a UI that let someone type in a SearchTerm and then click a Button and then that SearchTerm showed up in the right place in my ViewModel and the command executed and the navigation service attempted to navigate to another “page” in the app but failed because I hadn’t implemented a navigation service just yet.

Working on the Search Results Activity / Page

I added a new Android activity into my app for the search results page – I was pleased to see that there’s a “New Item” dialog to make this a little easier in the tooling;

image

and I also added a new layout (.axml) file to go alongside it. With that in place I needed to start working on some form of navigation service because the existing ViewModel from the first page is already calling into that service trying to navigate to the second page but, right now, there’s no code in the implementation.

Trying to Deal with “Navigation”

I hit an “interesting” small challenge here. My first thought was to implement my navigation by using the StartActivity method which starts another Activity. However, it seemed that an Activity knew how to start a new Activity (i.e. there’s a base class method which does it) but my INavigationService is abstracted from that much like it was on Windows/Phone where it is the Frame that knows how to do navigation but I can’t build knowledge of these UI types in an interface that’s meant to cross-platforms.

I quickly figured that Activity.StartActivity is really just calling Context.StartActivity and that if I passed the Context into my INavigationService implementation then that might be used to start Activity instances. This is almost exactly what I do on Windows/Phone except on those platforms I pass a Frame down into the implementation via a method RegisterFrame(). So, for Android I’ll be making a call to RegisterFrame() from the application code but I won’t actually be registering a Frame in that call, I’ll be registering a Context. It means that the method is now badly named but I’ve got that goal of not changing any of my portable code.

My first attempt to use ApplicationContext.StartActivity resulted in an exception which caused me to realise a little bit more about the template’s use of the ActivityAttribute class on my Activity classes and to read this document which explained how this is used to generate additional elements into the manifest file at build time. The exception had caused me to start wondering whether I needed to manually edit the manifest file to include my Activity classes but it turns out that Xamarin is making that easier for me via this attribute.

The exception I got was;

"Calling startActivity() from outside of an Activity  context requires the FLAG_ACTIVITY_NEW_TASK fla…"

and so I went off looking for what that might mean and figured out that the second “page” of my application was fast become an independent entity as far as the operating system was concerned and I wasn’t too keen on this so I backtracked but it was an educational diversion Smile

I had to change tack on passing the ApplicationContext into my INavigationService implementation and, instead, I passed the starting Activity of the app. I’m not sure if that’s a bad thing to do – I’m currently in the “conscious incompetence” phase here so I don’t know how bad a decision this is. I have a nagging doubt that something to do with Activity lifecycle is likely to bite me down the line because of this choice. “Fools rush in…”.

Taking that approach at least allowed me to get to a place where the search page navigated to the search results page Smile Later on, I wondered whether I should be making use of Application.Context rather than passing the Activity into this code but it worked “for now” so I stuck with it.

That search results page now just needed to display the data that the ViewModel surfaces so it was time for another bit of “UI” work.

At the point where I came to be trying to make my “binding” code work with a TextView (having built it to work with an EditText) I was really pleased to find that an EditText was derived from a TextView. A nice bonus and so I could rework a little code there rather than having to write more code.

I also had to implement the bare minimum around my INavigationService implementation such as to make sure that the navigation parameter passed from the search page was obtainable via the navigation service from the search results page. While I’d implemented this using a stack on Windows/Phone, I left things “simpler” here for Android and just made sure that the last parameter passed to navigation was available via the INavigationService.NavigationParameter property.

Displaying a Grid of Results

With that in place, I started to focus more on how I actually displayed the results on this page and had to do a little bit of reading around GridView and the whole idea of Adapters.

Initially, I couldn’t quite figure how to achieve something similar to what I’d do in a XAML based app where I’d use some kinds of ItemsControl, assigning a collection into its ItemsSource property and then specify an ItemTemplate to display for each item that the control finds in that collection.

I spent a little time trying to figure out how Android put together the various pieces like a GridView control, an ArrayAdapter and some kind of View and I built some bits and the rebuilt them while trying to get the idea of it.

I also got slightly bogged down because around this time my HTTP code started executing and (even though I’d requested the INTERNET) permission I was seeing regular failures in terms of resolving DNS names;

image

I’m not sure why this is – I could take the HTTP request that I was trying to make from code, paste it into the browser on device and everything was fine but, for some reason, 9/10 times my HTTP request from code was failing which made trying to debug anything a bit tedious. I’d also find that Visual Studio would crash quite a lot when trying to debug this scenario.

What was interesting with this one was that I found that running the code on the device without the debugger would always work fine but introducing the debugger would seem to cause a DNS resolution exception to be thrown. I’ve yet to figure this out at the time of writing.

In trying to get this working, I spent a bit of time trying to understand the different layout panels (Frame, Table, Absolute, Linear, Relative, etc) and how various properties affect layout within them. There’s a lot of options here but I think it’s fair to say that the same is true in XAML, I’ve just spent a long time with XAML so kind of know what I need to know in that world whereas I was fumbling around in Android.

I also spent a long time trying to get the ImageView control to display an image from the web via its SetImageUri() method before I realised (I think) that the ImageView doesn’t display images from the web, it wants you to manually download them first. This was a bit of a surprise to say the least.

At the end of all that, I’ve got 2 views kind of working albeit no doubt with horrible performance and lots of event handlers left hanging where they shouldn’t be;

device-2014-03-03-130548device-2014-03-03-130611

and new GridView ultimately involved only this small bit of XML (I’m embarrassed how long it took me to get that into any kind of shape);

<?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"
    android:background="@drawable/backdrop"
    android:minWidth="25px"
    android:minHeight="25px">
    <TextView
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/txtSearch"
        android:textSize="32dp"
        android:layout_marginTop="6dp"
        android:layout_marginBottom="12dp"
        android:background="@android:color/darker_gray" />
    <GridView
        android:numColumns="auto_fit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnWidth="166dp"
        android:id="@+id/gridResults"
        android:horizontalSpacing="10dp"
        android:verticalSpacing="10dp" />
</LinearLayout>

and each item in the GridView is displayed with this piece of XML;

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/relativeLayout1"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:padding="5dp"
    android:background="@android:color/black">
    <ImageView
        android:layout_height="166dp"
        android:id="@+id/imgPicture"
        android:layout_width="166dp"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true" />
    <TextView
        android:text="TextView"
        android:layout_height="wrap_content"
        android:id="@+id/txtTitle"
        android:layout_width="wrap_content"
        android:layout_below="@+id/imgPicture"
        android:layout_marginTop="1dp"
        android:layout_centerHorizontal="true"
        android:textSize="18sp"
        android:ellipsize="marquee"
        android:singleLine="true" />
</RelativeLayout>

and the Activity code which lives behind it is not something I could claim any pride over – it’s doing some nasty things right now but it currently looks like;

namespace AndroidApp
{
  using Android.App;
  using Android.Graphics;
  using Android.OS;
  using Android.Widget;
  using AndroidApp.Utility;
  using CrossPlatform.ViewModel;
  using System.Windows.Input;

  [Activity(Label = "flickrdemo.pages.searchresults", MainLauncher = false, Exported = false)]
  public class SearchResultsPageActivity : Activity
  {
    SearchResultsPageViewModel viewModel;

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

      // Create your application here
      this.SetContentView(Resource.Layout.SearchResultsPage);

      TextView txtView = this.FindViewById<TextView>(Resource.Id.txtSearch);
      GridView gridResults = this.FindViewById<GridView>(Resource.Id.gridResults);

      this.viewModel = ServiceLocation.Locator.Resolve<SearchResultsPageViewModel>();

      FakeBinding.ManualBindTextView("SearchTerm", this.viewModel, txtView);

      GridViewBinding<SearchResultViewModel> binding =
        new GridViewBinding<SearchResultViewModel>(
          this,
          "SearchResults",
          this.viewModel,
          Resource.Layout.SearchResultsPageItem);

      binding.Bind(gridResults,
        async (item, view) =>
        {
          // This is horrible. Lots of downloads, no ordering, bit of a mess. Would need
          // to revisit this and do it right I think - i.e. I'm not at all sure that
          // I feel "good" about this downloading happening here.
          TextView txtTitle = view.FindViewById<TextView>(Resource.Id.txtTitle);
          txtTitle.Text = item.Title;

          Bitmap bitmap = await ImageDownloader.DownloadFromWebAsync(item.ImageUrl, 166);

          if (bitmap != null)
          {
            ImageView imgView = (ImageView)view.FindViewById<ImageView>(Resource.Id.imgPicture);

            imgView.SetImageBitmap(bitmap);
          }
        });

      gridResults.ItemClick += (s, e) =>
        {
          ICommand cmd = this.viewModel.SearchResults[e.Position].InvokeCommand;
 
          if (cmd.CanExecute(null))
          {
            cmd.Execute(null);
          }
        };
    }
  }
}

and so it’s (again) mostly “glue” code to attempt to match up the world of XAML and its bindings with Android and its adapters. In doing this, I added more code to my FakeBindings class and another class altogether called GridViewBinding to try and centralise some of the code involved in “binding”. As I say, it’s a bit nasty at this point – it would need a bit more work to get it into shape and a much better understanding of how Android controls work.

That said, I’ve got my second screen visible, running and tapping on an item navigates to my third screen – it’s rough but it’s just about staying upright Smile

Working on Photo Details Activity/Page

The last page in this app is just a page which displays a selected photo at a larger scale along with its title. I followed the same routine for adding a new UI layout into the project calling it PhotoDetailsPageActivity.axml and adding the Activity derived class to go alongside it.

And to get that third “view” up and running took about 5 minutes. I ended up with a new UI definition;

<?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"
    android:background="@drawable/backdrop"
    android:minWidth="25px"
    android:minHeight="25px">
    <TextView
        android:text="Large Text"
        android:textAppearance="?android:attr/textAppearanceLarge"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:singleLine="true"
        android:id="@+id/txtTitle"
        android:textSize="32dp"
        android:layout_marginTop="6dp"
        android:layout_marginBottom="12dp"
        android:background="@android:color/darker_gray" />
    <ImageView
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/imgPicture" 
        android:scaleType="centerCrop"/>
</LinearLayout>

and a little bit of code to go alongside it and a minor tweak to my navigation service to tell it that it was ok to navigate to this new page – I also added some more code to my FakeBinding class to bind up an ImageView. The code that’s wiring up “bindings” is fast becoming where I’m hiding all my nasty little implementation mistakes and lack of knowledge.

Here’s the Activity code – just creates the UI, creates the ViewModel and then attempts to wire them together a little;

namespace AndroidApp
{
  using Android.App;
  using Android.OS;
  using Android.Widget;
  using CrossPlatform.ViewModel;

  [Activity(Label = "flickrdemo.pages.searchresults", MainLauncher = false, Exported = false)]
  public class PhotoDetailsPageActivity : Activity
  {
    PhotoDetailsPageViewModel viewModel;

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

      this.SetContentView(Resource.Layout.PhotoDetailsPage);

      this.viewModel = ServiceLocation.Locator.Resolve<PhotoDetailsPageViewModel>();

      TextView txtTitle = this.FindViewById<TextView>(Resource.Id.txtTitle);
      ImageView imgPicture = this.FindViewById<ImageView>(Resource.Id.imgPicture);

      FakeBinding.ManualBindTextView("Title", this.viewModel, txtTitle);
      FakeBinding.ManualBindImageView("ImageUrl", this.viewModel, imgPicture);
    }
  }
}

and so now I’ve 3 screens in my “app”;

device-2014-03-03-130548device-2014-03-03-130611device-2014-03-03-133656

Adding the Ability to Save a Picture

The original “app” had one more ability – on that last screen there’s an implementation of ICommand kicking around which is waiting to be bound up to some UI button and then that command attempts to save the photo in question to the file system.

I wasn’t entirely sure where to add a “save” button. I looked at the Action Bar and it didn’t feel to be too much of a violation of the design guidelines to add a button to it but it wasn’t immediately obvious how I accessed it and I kept on reading coming across the write up around the options/panel menus and so I decided to take a look at that and found that it seemed to be a matter of overriding the OnCreateOptionsMenu method on my PhotoDetailsPageActivity;

    public override bool OnCreateOptionsMenu(Android.Views.IMenu menu)
    {
      MenuInflater.Inflate(Resource.Layout.PhotoDetailsOptionsMenu, menu);

      return base.OnCreateOptionsMenu(menu);
    }

and then authoring a little more .axml in the shape of a menu;

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:id="@+id/savePhoto"
        android:icon="@android:drawable/ic_menu_save"
        android:title="@string/savePhoto" />
</menu>

and that seemed to work ok in terms of getting the menu onto the screen – next step was just to make sure that when clicked that option would execute the right command on my ViewModel which was really just a matter of adding another override (which was a bit of a surprise having looked at IMenuItem);

    public override bool OnMenuItemSelected(int featureId, IMenuItem item)
    {
      if (item.ItemId == Resource.Id.savePhoto)
      {
        this.viewModel.SaveCommand.Execute(null);
      }
      return base.OnMenuItemSelected(featureId, item);
    }

with that in place, I “just” needed to implement the IPhotoSavingService which I stubbed out when I first started the Android implementation.

I hit a minor stumbling block – I wasn’t quite sure where the right place was on Android to save a photo such that it showed up in a “library” or “gallery”. I scanned through all the application manifest permissions thinking that there might be something in there which related to reading/writing the photos library but there wasn’t.

I had a bit of a flick through this article: http://developer.android.com/training/camera/photobasics.html and figured that making use of getExternalStoragePublicDirectory() with a DIRECTORY_PICTURES argument was the right thing to do and that I’d be needing WRITE_EXTERNAL_STORAGE in order to be able to do that so I modified the manifest for that;

image

and then set about seeing if I could make use of the Android.OS.Environment class to get hold of a file in a pictures folder which seemed to work out ok although I found myself muddling through lots of different types of Uri and File classes;

using Android.App;
using Android.Content;
using AndroidApp.Utility;
using CrossPlatform.Service;
using System;
using System.IO;
using System.Threading.Tasks;

namespace AndroidApp.Service
{
  class PhotoSavingService : IPhotoSavingService
  {
    public async Task SavePhotoToPicturesLibraryAsync(Uri pictureUrl)
    {
      byte[] bits = await ImageDownloader.BitsFromWebDownloadAsync(pictureUrl.ToString());

      using (Java.IO.File file = Android.OS.Environment.GetExternalStoragePublicDirectory(
        Android.OS.Environment.DirectoryPictures))
      {
        string path = Path.Combine(file.Path, Path.GetFileName(pictureUrl.LocalPath));

        // may well throw...
        using (FileStream fileStream = new FileStream(path, FileMode.OpenOrCreate))
        {
          await fileStream.WriteAsync(bits, 0, bits.Length);
          await fileStream.FlushAsync();

          // tell the system about it.
          NotifyMediaScan(path);
        }
      }
    }
    void NotifyMediaScan(string path)
    {
      // starting to be too many definitions of File, Uri for me here :-)
      Intent mediaScanIntent = new Intent(Intent.ActionMediaScannerScanFile);

      using (Java.IO.File file = new Java.IO.File(path))
      {
        mediaScanIntent.SetData(Android.Net.Uri.FromFile(file));

        // Feels bad to be reaching out to this context from here :-(
        Application.Context.SendBroadcast(mediaScanIntent);
      }
    }
  }
}

and so now if I save a picture from the app;

image

then it shows up in the Photos app on the device straight away;

image

and that’s good Smile

Wrapping Up

I’ve been fumbling my way through the basics of trying to get this simple “app” onto Android and I’ve had quite a good time although it’s been frustrating in places. On the way, I’ve learned some things about Xamarin and about Android. On the plus side;

  1. I think it is of massive benefit to me to be able to try and do this work in Visual Studio.
  2. I think it is of massive benefit to me to be able to try and do this work in C#.

and what I’m really saying is that even with this small code base which doesn’t really work properly (i.e. takes no notice of performance and takes no notice of application lifecycle) I think it would have taken me a lot, lot longer to attempt to move it across to Android without using Xamarin. I think keeping as many of the variables fixed as possible helps massively and trying to play around with Java and another IDE while trying to move this code would have been a lot harder. I’ve done some bits that way before and I know that this approach felt a lot more familiar.

Also on the plus side – I think that having this code reasonably well structured and packaged into a portable class library helped me massively. Most of my work has been about wiring up agnostic ViewModels to a new UI and trying to glue things between the two.

Finally, on the plus side – I’ve learned some things about Android and I think there’s a lot of positives for me there. Some things I’d highlight;

  1. The docs are good.
  2. I like the simplicity of the way in which UIs can be defined in XML and just loaded up and toyed with – it feels a bit less “black box” than the XAML approach although I’m going to come back and call this a downside in a moment.
  3. The lifecycle of deploying from Xamarin to device and then debugging has proved pretty good – I’ve had one or two crashes here and there but nothing that’s got in the way of making progress.

On the downside – I’ve learned some other things about Android;

  1. What on Earth is going on with the layout system? There are properties everywhere and I’ve yet to find a really, really good article that explains them all.
  2. The emulators caused me a lot of pain both in performance and stability although to be fair I’ve had more success with them in the past.
  3. I found the experience of trying to define what is essentially a GridView with an ItemsTemplate to be a bit tedious. The way that I worked here was to author 2 .axml layout files and then I’d find that the only way to see what this looked like at run time was to actually run the app and then tweak a few settings and re-run it. I also found that some of those settings are incompatible with others so I’d run the app only to have it crash and then I’d have to try and figure out what went wrong from the exception message for what was, really, a design-time problem.
  4. I was surprised that there aren’t more, walk-through articles out there generally on the web beyond the Google docs and Xamarin’s docs. I spent quite a lot of time searching the web for posts relating to “using GridView with a TableLayout” and I didn’t really find what I wanted. I found a lot of “Hello World” style posts but nothing with any meat and nothing that seemed to touch on the scenario I was trying to deal with. That surprised me given how many Android developers and apps are out there.

What would improve the experience for me?

  1. Since most of the code that I wrote was around binding up ViewModels to UI controls, I clearly needed a cross-platform MVVM framework like MvvmCross. I knew this before I started but I wanted to do things in a bit of a manual way in order to see what that felt like and to try and learn a few lessons.
  2. MvvmCross would cut down the additional code that I had to write on the Android side and, generally, I’d like to see that cut down even more and perhaps see “someone” implement more library support for things like saving files that spans across the platforms. I don’t know who that “someone” might be but Xamarin feel like the perfect candidates to me.

That’s it – I’m going to put away the Android device for a day or two although I might revisit this code a little to see if I can tidy up some of the mess I’ve left.

Code

Visual Studio’s view of the code at the end of that process was as below – not sure how helpful that is but I thought it was interesting Smile

image

The code’s available here for download – naturally, it’s not going to bear up to any criticism or win any awards but it was a useful exercise for me.


Posted Mon, Mar 3 2014 4:27 PM by mtaulty

Comments

Mike Bluestein wrote re: Baby Steps on Android with Xamarin–Part 4
on Mon, Mar 3 2014 6:20 PM

Nice article series Mike! For file I/O, another option is to use Isolated Storage, which we've implemented on both Xamarin.iOS and Xamarin.Android.

Also, for a better (faster) emulator experience, check out Genymotion. Scott Hanselman has a blog post showing how to deal with this if you're using Hyper-V for Windows Phone dev as well:

www.hanselman.com/.../SwitchEasilyBetweenVirtualBoxAndHyperVWithABCDEditBootEntryInWindows81.aspx

mtaulty wrote re: Baby Steps on Android with Xamarin–Part 4
on Tue, Mar 4 2014 11:19 AM

Thanks Mike but isolated storage wouldn't get me what I wanted here which was to store files into the photos library?

Mike.

Mike Bluestein wrote re: Baby Steps on Android with Xamarin–Part 4
on Tue, Mar 4 2014 2:23 PM

Ah, right. that will only get you general purpose file I/O. Splat has image saving and loading to an extent. I think in it's current form you'd still have to provide the target to save to the native photo libraries, but maybe it's something you could fork (even just having the cross-platform image loader is nice though). github.com/.../splat

Steve Chadbourne wrote re: Baby Steps on Android with Xamarin–Part 4
on Tue, Mar 4 2014 8:14 PM

MvvmCross is definitely the way to go. Moves loads of code from the code behind to the view model in the portable library. They have lots of plugins including a cross platform save file one.

Cyril Cathala wrote re: Baby Steps on Android with Xamarin–Part 4
on Wed, Mar 5 2014 11:34 AM

You should definitely check MvvmCross, it simplifies many things.

And with the framework come along many plugins filling the gaps and the need for crossplatform API. There are plugins for I/O, settings, sqlite, email, phone, etc. Check for yourself : www.nuget.org/packages

It might not be perfect for all situations, but it's extensible and very flexible, it kind of reminds me the good old days with Prism and Silverlight :)

And +1 for Genymotion, best emulator for Android.

Anonymous wrote re: Baby Steps on Android with Xamarin–Part 4
on Wed, Mar 5 2014 11:04 PM

Great post! As someone that is trying to move into the Android world as an experienced Windows developer, this is very useful :)

The photo saving service looks incomplete in the code download. Are you sure the download is the completed code that you've referenced in your article?

Mike Taulty's Blog wrote Baby Steps on Android with Xamarin–Part 5
on Tue, Mar 11 2014 2:47 PM

Following up on the previous post , it was pretty obvious that where any “work” really arose in implementing