Using Inversion of Control in MonoDroid Applications

Just because a mobile application needs to be (or should be, in most cases) small and lightweight doesn’t mean we should set aside best practices like Inversion of Control containers when building our apps. I don’t want this to be an introduction to dependency injection, so I’d highly recommend reading up on it a bit if you aren’t familiar with the pattern. With so many options out there for .NET containers, which ones should we use? In this article I’ll go over some good options I’ve found for using dependency injection in MonoDroid applications.

Update (12/13/2011): Updating to work with Mono for Android 4.0

When looking for containers to try out, my main goal was to find something really lightweight. I don’t typically need too much complexity from my containers, so I wanted something that give me that layer without much baggage. I have used Ninject before and quite like it (how can you not like ninjas?), but didn’t go down that route since it seemed I wouldn’t be able to leverage a lot of its power on Android. I was able to get it to compile against MonoDroid, so it should be possible. One disappointing thing I found was that Android doesn’t seem to expose any hooks into the creation process for components (something like ASP.NET MVC’s ControllerFactory), which would have made for a perfect injection point.

The two containers I decided to go with were TinyIoC and Funq. I will talk about each later in the article, but first let’s set up our sample application and pattern.

The Application

The sample application here will be simple, with a big button that picks a new quote from a particular movie and displays it. Different movie quote providers can be done by implementing IMovieQuoteProvider:

public interface IMovieQuoteProvider
{
  string GetQuote();
}

We’ll implement two providers, for The Big Lebowski and Spaceballs. Here is one of them (with some quotes cut out), but you can see everything in the sample project at the end:

public class TheBigLebowskiQuoteProvider : IMovieQuoteProvider
{
  private Random _randomNumberGenerator;

  public TheBigLebowskiQuoteProvider()
  {
    _randomNumberGenerator = new Random();
  }

  private string[] _quotes = { "Mark it, Dude." };

  public string GetQuote()
  {
    return _quotes[_randomNumberGenerator.Next(0, _quotes.Count() - 1)];
  }
}

Now we can move on to actual Android code. Since we want to use the container globally across the application, that means we want it to get loaded when the application first starts up, before any activities get fired up. To do that, we can subclass Android.App.Application and decorate it with ApplicationAttribute. You can only have one class with that attribute in your application or it won’t compile.

[Application]
public class DemoApplication : Application
{
  public DemoApplication(IntPtr handle, JniHandleOwnership transfer)
    : base(handle, transfer)
  {
  }

  public override void OnCreate()
  {
    base.OnCreate();
  }
}

Next, let’s define the layout for the main (and only) activity in Resources/layouts/main.xml:

<?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/generate"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="New Quote" />
  <TextView
    android:id="@+id/quote"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" />
</LinearLayout>

Last but not least, the activity:

[Activity(Label = "IoC Demo", MainLauncher = true)]
public class DemoActivity : Activity
{
  private IMovieQuoteProvider _quoteProvider;
  private Button _generateButton;
  private TextView _quoteText;

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

    SetContentView(Resource.layout.main);
    _generateButton = FindViewById<Button>(Resource.id.generate);
    _quoteText = FindViewById<TextView>(Resource.id.quote);

    _generateButton.Click += delegate
    {
      _quoteText.Text = _quoteProvider.GetQuote();
    };
  }
}

When the button is clicked, the IMovieQuoteProvider will be used to get the next quote. All that’s left is to inject the implementation.

TinyIoC

First up is TinyIoC, which truly lives up to its name. One of the nice things about TinyIoC is that it is totally contained within a single C# file, making it trivial to include in any project without having to worry about references, and it is designed to work properly on many platforms. Despite being “small”, it still has a nice fluent API as well as some auto-registration features. I’m only going to go over a very simple use case, so I encourage reading more if you like this approach.

Let’s go back into DemoApplication and set up the container. We’ll add a function initTinyIoC(), and call it from OnCreate():

public override void OnCreate()
{
  base.OnCreate();

  initTinyIoC();
}

private void initTinyIoC()
{
  TinyIoCContainer.Current.Register<IMovieQuoteProvider>(new TheBigLebowskiQuoteProvider());
}

TinyIoC uses a singleton container that you can access anywhere in your application. Here we tell the container that whenever someone requests a IMovieQuoteProvider object, it should hand them the instance of TheBigLebowskiQuoteProvider we supplied. If you wanted you could supply it with a factory method via a lambda expression instead of creating the object up front.

Now DemoActivity needs to pull the object out of the container. In the OnCreate() method, anywhere before the click handler, add:

_quoteProvider = TinyIoC.TinyIoCContainer.Current.Resolve<IMovieQuoteProvider>();

After that call, the activity’s private quote provider will be pointed at the one in the container, and we’re good to go. Fire up the app and you should be able to scroll through a handful of quotes from The Big Lebowski.

Funq

Never satisfied in having just one option, I turned to Funq next. At the time that this was written, Funq doesn’t officially support MonoDroid (which is still in private beta, so that’s not all that surprising). However, I found that the Windows Phone 7 version of it seems to work properly, so we’ll use that for now. If you’re compiling the source yourself, you can get it to compile correctly against the MonoDroid profile if you use the WINDOWS_PHONE build symbol. The reason is that MonoDroid lacks some of the System.Func<> delegates that are in newer versions of the full .NET Framework. Windows Phone 7 is missing the same ones, and Funq is set up to handle that properly in the build by defining the delegates itself. In the sample project I’m providing, I include and reference the WP7 version of Funq 1.0.

There isn’t much in the way of documentation for Funq, but there are plenty of unit tests provided which is just as good. Funq was originally created as part of the Mobile Application Blocks project, aiming to provide a fast and easy container with no use of reflection at all, which is a nice feature to have.

Back in DemoApplication, let’s add support for the Funq container. Funq doesn’t use a singleton container, so we’ll manage the instance ourself via a public property on the class, allowing it to be accessed by the activity.

public Container FunqContainer { get; private set; }

public override void OnCreate()
{
  base.OnCreate();

  initFunq();
}

private void initFunq()
{
  FunqContainer = new Container();

  FunqContainer.Register<IMovieQuoteProvider>(new SpaceballsQuoteProvider());
}

Just like we did with TinyIoC, the container will now hand out the instance of SpaceballsQuoteProvider whenever someone requests IMovieQuoteProvider. In DemoActivity, change the line that uses TinyIoC to use the Funq container:

_quoteProvider = ((DemoApplication)Application).FunqContainer.Resolve<IMovieQuoteProvider>();

This time when you fire up the app, you should see quotes from Spaceballs.

Hopefully this helped give you an idea of how to easily start using dependency injection in your MonoDroid applications. Which container do you prefer? You can download all of the code from this article here.

Tags: ,

8 Responses to “Using Inversion of Control in MonoDroid Applications”

  1. Using Inversion of Control in MonoDroid Applications…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

  2. [...] This post was mentioned on Twitter by ajlopez, Greg Shackles and others. Greg Shackles said: @Grumpydev Here you go :) http://shackl.es/eL3tgt [...]

  3. Hi, I just stumbled upon this post when looking for information on using a IoC container in an Android application.
    I haven’t used Monodroid yet, so this don’t apply for my case, but as I’m here I’d like to point you to a project that I’ve developed to work with Windows CE devices… maybe you can retarget it to use with monodroid: http://code.google.com/p/compactcontainer/
    Kind regards.

  4. Really nice stuff

  5. Lee Oades

    Nice. I take it there is no way to override the object that creates the Activities to provide constructor DI?

  6. Unfortunately not, that would be far too convenient :) Android is very inheritance driven and there’s no hooks for any of that.

    At one point I had started working on a framework to make it easier, something similar to what Roboguice does for Java Android. I’m hoping to pick that project back up in the near future.

  7. Mohib Sheth

    Thank you for the article. It really helped me understand the usage.

  8. [...] that I found that discussed implementing IoC with these frameworks in Xamarin for Android was here. In this article Greg Shackles reviews both TinyIoC and Funq as well as providing some really solid [...]

Leave a Reply