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

Blogs

Mike Taulty's Blog

Elsewhere

Archives

Following up on the previous post, it was pretty obvious that where any “work” really arose in implementing my little 3-page simple “app” on Android was in two areas;

  1. Implementing the platform specific views for Android.
  2. Implementing the platform specific services for Android – in my case, this involves writing a navigation service and a photo-library file saving service.

Step 1 involves a certain amount of creating a platform-specific UI which there’s no getting away from but it also involved an amount of work in transporting data (and commands) from that UI to my ViewModels.

On a XAML-based platform, that’s something that pretty much happens automatically. On the Android platform, it took manual code (no criticism of Android – it just works differently here).

To some extent, I was re-inventing some small pieces of a wheel and I did it deliberately to get a feel of what that work was like but I know that there are frameworks/products out there that add some level of XAML-like binding between the Android UI layer and the ViewModel layer. Examples of those might be;

There are probably some more but I’ll declare “an interest” here and say that I know Stuart, he’s a friend of mine and we’ve done events together in the UK and MvvmCross is the framework that I hear most about in this context of Xamarin and C# MVVM across platform so I thought I’d experiment with MvvmCross.

What I specifically wanted to figure out was – without changing the code that I already have in my portable library, is it possible to use MvvmCross in only my Android project to take away some of the code that I had to write in that project to achieve the most basic level of binding and perhaps some other services (like navigation and/or file saving).

I thought I’d give it a whirl and see what the outcome was…

Adding MvvmCross as a Nuget package to my Android app was an interesting thing to do – MvvmCross seems to be pretty much taking over Nuget with its list of packages Smile

image

and the highlighted items give a pointer to the architecture of MvvmCross – there are plugins for native functionality such that each developer can avoid having to re-invent the wheel in implementing a particular piece of functionality for N platforms.

While I’ve watched Stuart demonstrate MvvmCross, I’m still a complete beginner here so I went for the “Getting Started” package and it added a whole bunch of assemblies into my Android project;

image

Having installed those assemblies, I didn’t really have much of a clue what to do with them so I went to the Wiki and the first thing that caught my eye was;

The Manifesto

I like a framework to come with a good Manifesto Winking smile Actually, it’s a nice document and there’s nothing in there that I disagree with and I especially like;

  • Your opinions matter – you should be able to override any part of MvvmCross, including its opinions.

and I’m hoping that what that means is that, for this particular example, I can bolt in the bits of MvvmCross that I want without having to change any of the portable code that I’ve already got.

I then read;

High Level MvvmCross Objects

which I think told me that it’s normal for an MvvmCross application to have;

  • one portable “core” implemented as a PCL which would contain ViewModels, Models, Services and App objects.
  • multiple “ui” projects which contain setup code, views, presenter and a native Application object.

Now…in my case I don’t want the portable “core” to contain the App object because I want to leave my portable “core” code alone. I’m hoping that I can just do that work inside of the Android project while accepting that it might duplicate some of the code that I’ve got in my portable library already.

I also learned that MvvmCross has its own IoC container but I spotted from the IoC document that I might be able to wire up what I’ve already got as an IMvxIoCProvider.

Finally, I learned that ViewModels are normally in a folder called ViewModels that they normally inherit from MvxViewModel. I’m hoping that the use of “normally” means that those things are flexible (I suspect that they are) and that I’ll be needing some kind of Presenter but it sounds like I’ll be able to make use of a default there.

Tidying Up

When I started looking properly at my code, I realised that adding in the “Getting Started” package from Nuget had done more things to my project than I thought. Specifically, a whole bunch of stuff had shown up;

image

plus (because it wouldn’t all fit on one screen);

image

and so I reviewed what was in those files and got rid of some of them (e.g. the FirstView related files) but, mostly, I welcomed them because it’s easier to sit in Visual Studio and look at these files than it is to keep switching back-and-forth between Visual Studio and some docs which would largely then lead me through re-creating something very similar to what was already present in these files.

Getting Going – Trouble in the ViewModels?

From there, I thought it would be wise to move my Android views into the Views folder and to derive them from MvxActivity. I had to change my SearchPageActivity class such that it wasn’t marking itself as the MainLauncher because there was now a new SplashScreen activity which marks itself as the MainLauncher.

I added an App class derived from MvxApplication and then attempted to override Initialise() in order to create my first view/viewmodel. As far as I could work out, this involves making a call to MvxApplication.RegisterAppStart(). The “problem” I hit with this was that this code;

  class App : MvxApplication
  {
    public override void Initialize()
    {
      base.RegisterAppStart<SearchPageViewModel>();
    }
  }

but that code won’t compile because the framework expects that my view model would implement IMvxViewModel. Now, that interface feels entirely reasonable;

 public interface IMvxViewModel
  {
    MvxRequestedBy RequestedBy { get; set; }

    void Init(IMvxBundle parameters);
    void ReloadState(IMvxBundle state);
    void SaveState(IMvxBundle state);
    void Start();
  }

and it’s not dissimilar from the model that Prism for WinRT has for view models but, unfortunately, my view models are already built into my portable class library and I was really hoping not to have to change them and, because this is not a properly implemented application they;

  1. don’t need ReloadState/SaveState although they really should.
  2. implicitly wire together the idea of Init/Start as being done at construction time.

Clearly, IMvxViewModel implies a much better world than the one represented by my current view model implementations.

But what to do in order to avoid changing my portable code?

At first, I thought that I might be able to avoid this requirement by implementing my own IMvxViewModelLocator implementation but that still seems to have the requirement that the view models that it provides will implement IMvxViewModel.

I then considered changing my portable code. I could change all my view models to implement IMvxViewModel but that then means that my portable code would be taking a dependency on MvvmCross which I’m not using on the Windows/Phone platforms so I didn’t really want to do this.

At the same time that I was trying to figure out how to approach this, I was also trying to figure out what to do about the inversion of control container that my portable class library is already using – Autofac.  MvvmCross is pluggable in terms of accepting anything that implements IMvxIoCProvider but I think that’d mean doing a little bit more work to implement that interface over Autofac.

The first conclusion that I came to was that things would be easier if I was using MvvmCross across all my implementations but I wasn’t going to do that right now Smile

The second conclusion that I came to was that, for this particular slightly odd example, I might find it easiest to use the default IoC container that MvvmCross provides and then simply derive some Android-specific view models in my Android project which implement IMvxViewModel (albeit with a stubbed out implementation) and which derive from the real view models in the portable class library project.

For example – deriving an MvxSearchPageViewModel from the original portable SearchPageViewModel and adding in an implementation of IMvxViewModel to that derived class;

image

This seemed to work out pretty well and I went with that along with using the built-in IoC container of MvvmCross.

Getting the Initial View on Screen

I wanted to get to the point where I had that first view on the screen – the simple view that lets me enter a search term and click a button to begin navigation to the second view (whose ViewModel does the search). I managed to get my initial attempt at a Setup class for MvvmCross (in the Android project only) to be;

namespace AndroidApp
{
  using Android.Content;
  using AndroidApp.Service;
  using AndroidApp.ViewModels;
  using Cirrious.CrossCore;
  using Cirrious.CrossCore.Platform;
  using Cirrious.MvvmCross.Droid.Platform;
  using Cirrious.MvvmCross.ViewModels;
  using Cirrious.MvvmCross.Views;
  using CrossPlatform.Service;

  public class Setup : MvxAndroidSetup
  {
    public Setup(Context applicationContext)
      : base(applicationContext)
    {
    }
    protected override void InitializeFirstChance()
    {
      Mvx.RegisterType<IFlickrService, FlickrService>();
      Mvx.RegisterType<IPhotoSavingService, PhotoSavingService>();
      Mvx.RegisterSingleton<INavigationService>(new NavigationService());
    }
    protected override void InitializeViewLookup()
    {
      var viewsContainer = Mvx.Resolve<IMvxViewsContainer>();
      viewsContainer.Add(typeof(MvxSearchPageViewModel), typeof(SearchPageActivity));
    }
    protected override IMvxApplication CreateApp()
    {
      return (new App());
    }

    protected override IMvxTrace CreateDebugTrace()
    {
      return new DebugTrace();
    }
  }
}

and my App class is very short and sweet, just specifying the starting ViewModel (note that the previous InitializeViewLookup method is being used to associate View<->ViewModel here);

namespace AndroidApp
{
  using AndroidApp.ViewModels;
  using Cirrious.MvvmCross.ViewModels;

  class App : MvxApplication
  {
    public override void Initialize()
    {
      base.RegisterAppStart<MvxSearchPageViewModel>();
    }
  }
}

and I changed my .AXML UI definition to now include bindings!

image

and now the code that I wrote in the SearchPageActivity class now becomes mostly redundant as the work is being done by binding and I have a view without any “code behind” other than to load the UI definition;

namespace AndroidApp
{
  using Android.App;
  using Android.OS;
  using Cirrious.MvvmCross.Droid.Views;

  [Activity(Label = "flickrdemo.pages.search", MainLauncher = false, Icon = "@drawable/icon")]
  public class SearchPageActivity : MvxActivity
  {
    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);
      
      this.SetContentView(Resource.Layout.SearchPage);
    }
  }
}



and that gets me to the point where I can run the app, the first view loads after the “MvvmCross” splashscreen Smile and the single text box on that view binds its value into the underlying ViewModel and the single button on that screen binds its “command” such that when clicked it calls into the ViewModel and tries to use the underlying navigation service to navigate (with a parameter) to the next page in the app.

However…that navigation service isn’t yet reworked to do something sensible with MvvmCross…

Reworking the Navigation Service

In terms of navigating, MvvmCross has an ability to do “ViewModel to ViewModel navigation” which is what I want (i.e. I have my SearchPageViewModel and it’s now ready to navigate to the next view model (SearchPageResultsViewModel) passing along a parameter).

The MvxViewModel base class for view models derives from an MvxNavigatingObject class which “knows how to do navigation” – i.e. it has methods like ShowViewModel<T>( parameterValues ).

However…the ViewModel code that I have which is trying to do this navigation does so by calling an abstracted INavigationService which can be implemented differently on any platform. That ViewModel code is baked into my portable class library and I don’t want to change it.

What I want to do is somehow get hold of the functionality of MvxNavigatingObject outside of the context of an MvxViewModel and use it directly from my implementation of INavigationService.

I came across the MvvmCross idea of a view presenter (IMvxViewPresenter) and the Android specific version of this (IMvxAndroidViewPresenter) and I’d initially expected that this might be a service that the framework itself registered in the IoC container but it seems not to and so I made sure that when the view presenter is created at startup time, I manually register it myself so that other code can later look it up;

  public class Setup : MvxAndroidSetup
  {
    public Setup(Context applicationContext)
      : base(applicationContext)
    {
    }
    protected override IMvxAndroidViewPresenter CreateViewPresenter()
    {
      var presenter = base.CreateViewPresenter();

      Mvx.RegisterSingleton<IMvxViewPresenter>(presenter);

      return (presenter);
    }

That meant that my navigation service could look up the IMvxViewPresenter implementation and attempt to make use of it. For example, here’s my first attempt at getting my navigation service to work (bearing in mind that in this particular “app” navigating only involves moving to one of two pages);

    public void Navigate(string destination, string parameter)
    {
      IMvxViewPresenter presenter = Mvx.Resolve<IMvxViewPresenter>();

      Type type = destination == 
        Constants.SEARCH_RESULTS_PAGE ?
        typeof(MvxSearchResultsPageViewModel) : typeof(MvxPhotoDetailsPageViewModel); 

      this.navigationParameter = parameter;

      var request = new MvxViewModelRequest()
      {
        ViewModelType = type
      };

      presenter.Show(request);
    }

that actually worked fine but I hit a problem with the page that is being navigated to from the initial page which is represented by the SearchResultsPageActivity class and its associated SearchResultsPageViewModel (which surfaces a collection of seach results in a class called SearchResultViewModel).

That Difficult Second View

The basic problem that I hit is that having derived an MvxSearchResultsPageViewModel (as previously described) from the original SearchResultsPageViewModel left me with a constructor that looked like this;

    public MvxSearchResultsPageViewModel(IFlickrService flickrService,
      INavigationService navigationService,
      Func<SearchResultViewModel> searchResultViewModelFactory)
      : base(flickrService, navigationService, searchResultViewModelFactory)
    {
      
    }

with the problem here being the third parameter.

That third parameter is asking for the IoC container to inject a factory function which knows how to create a SearchResultViewModel because this ViewModel needs to do that with all of the results that come back from calling the search service. However, I’m not sure whether the IoC container that’s built into MvvmCross supports that kind of constructor injection. I had a flick through the docs on the IoC features and didn’t find it listed.

I think this is one of those cases where I don’t quite have the right abstraction for the job in hand but the fact that I have an abstraction at all is helpful. So, rather then define the sub-class constructor as it is above I can maybe make it dependent on a new interface;

  interface IFactory<T>
  {
    T Construct();
  }

and have that constructor take a dependency on an IFactory<SearchResultViewModel> as below and pass the Construct function through to the base class when it constructs that class;

  class MvxSearchResultsPageViewModel : SearchResultsPageViewModel, IMvxViewModel
  {
    public MvxSearchResultsPageViewModel(
      IFlickrService flickrService,
      INavigationService navigationService,
      IFactory<SearchResultViewModel> viewModelFactory) :
 
        base(flickrService, navigationService, viewModelFactory.Construct)
    {
      
    }

and then it just becomes a matter of making sure that there is an implementation of IFactory<T> (which can presumably just call Mvx.Resolve<T>()) injected into the IoC container which was easy to do so, with that, I’d just about managed to steer my way around this particular corner that I’d boxed myself into.

That moved that particular problem out of the way. The next step was to remove pretty much all the code from my SearchResultsPageActivity class, leaving only;

namespace AndroidApp
{
  using Android.App;
  using Android.OS;
  using Cirrious.MvvmCross.Droid.Views;

  [Activity(Label = "flickrdemo.pages.searchresults", MainLauncher = false, Exported = false)]
  public class SearchResultsPageActivity : MvxActivity
  {
    protected override void OnCreate(Bundle bundle)
    {      
      base.OnCreate(bundle);

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

which I was very happy to see and then to update my .AXML file for that view to include bindings and I was even happier to see the MvxGridView control;

image

and that’s quite a leap forward because I go from having to manually produce data for a grid control to simply specifying that the control binds its ItemsSource to a ViewModel property called SearchResults. Very, very nice.

I also needed to amend the template that is displayed for each item in the GridView;

image

and these two files represent quite a lot less hassle in terms of getting data onto the screen – everything’s now data-bound rather than writing looping code to populate data for display. Once again, a whole bunch of my hacked code from the previous blog post goes into the bin.

One thing that did stump me for a while was that in binding the ImageUrl of the MvxImageView above, I found that the binding seemed to work (i.e. I could see the engine pulling values from my ImageUrl property) but images didn’t display – I would see a grid view with the right layout and the right titles but no images displayed.

I spent a little while on this before I finally attached the “Dalvik Debug Monitor” with the intention of trying to see if I could monitor the network traffic but, it showed me some tracing messages which were visible in Visual Studio all along if only I’d taken a look;

image

so that told me what I was missing. What I then figured out was that I needed an additional plugin – the DownloadCache.Droid plugin which (from glancing at its code) looks like it will register various classes relating to downloading and caching images.

That caused me to then go and read the plugins page and then to go and try to install the right plugin;

image

which I noticed added another file to my project;

image

with code;

    public class DownloadCachePluginBootstrap
        : MvxPluginBootstrapAction<Cirrious.MvvmCross.Plugins.DownloadCache.PluginLoader>
    {
    }

which is how, I believe, plug-ins are registered – it feels a little “odd” to me to have plugins discovered by the framework reflecting onto the assembly ( rather than e.g. using some XML configuration file ) but that’s how it works so I’m happy enough to go along with it.

Bringing in the download cache plugin gave me an error;

image

which made me think that there’s a dependency on a file plug-in so I went off to get that one too;

image

which seemed to solve the problem and I finally managed to get images bound onto the screen without writing any code whatsoever in my Activity class and working in pretty much the exact same way as I’d work in a Windows/Phone XAML based app – very, very nice.

The Last View

With that in place, I just needed to implement the last view in my app which displays a larger image and offers the user a chance to save that image into the file system (pictures library). By this point, the mechanics are becoming pretty well understood;

  1. Remove the old, manual code that I had in my Activity class as MvvmCross binding will replace it.
  2. Edit my .axml file in order to add that binding.
  3. Register the association between my View and my ViewModel via the Setup.InitializeViewLookup override (which I’m using because of the peculiarity of the way things have been set up and named).

and that worked perfectly and once I’d changed this code all of the code that I’d written in my FakeBinding class was now redundant and I managed to remove it along with a ServiceLocation class I’d written as I’m now relying on the MvvmCross IoC container to do that for me.

This last view does have a menu item to allow the saving of the photo on the screen to the pictures library which involves downloading the picture again from the web first.

Ideally, I’d make use of a plug-in to replace this functionality but scanning the list of plugins I didn’t see anything that would immediately do what I wanted although the File plug-in might help a little and the Picture plug-in looked attractive but it only picks pictures rather than saving them to the right place.

So, for the moment I’m leaving a little code in my View (Activity) to set up the menu handling and to call the ViewModel’s command when the user taps on that menu item;

namespace AndroidApp
{
  using Android.App;
  using Android.OS;
  using Android.Views;
  using Cirrious.MvvmCross.Droid.Views;
  using CrossPlatform.ViewModel;

  [Activity(Label = "flickrdemo.pages.searchresults", MainLauncher = false, Exported = false)]
  public class PhotoDetailsPageActivity : MvxActivity
  {
    public override bool OnCreateOptionsMenu(Android.Views.IMenu menu)
    {
      MenuInflater.Inflate(Resource.Layout.PhotoDetailsOptionsMenu, menu);
     
      return base.OnCreateOptionsMenu(menu);
    }
    public override bool OnMenuItemSelected(int featureId, IMenuItem item)
    {
      if (item.ItemId == Resource.Id.savePhoto)
      {
        // bit ugly...
        ((PhotoDetailsPageViewModel)this.ViewModel).SaveCommand.Execute(null);
      }
      return base.OnMenuItemSelected(featureId, item);
    }
    protected override void OnCreate(Bundle bundle)
    {
      base.OnCreate(bundle);

      this.SetContentView(Resource.Layout.PhotoDetailsPage);
    }
  }
}

and then I have specific code in my IPhotoSavingService which saves the photo into the pictures library and I haven’t changed that code at all in the light of MvvmCross just yet – it’s doing what it was doing in the previous post.

Wrapping Up

It was a “fun” exercise to take that simple code that I’d written before and to add MvvmCross into the mix. In places, I have some code that’s no longer being used on Android (e.g. the code that I use to build up an Autofac IoC container) and in some other places I had to do a little more work (e.g. pretending that my ViewModels implement IMvxViewModel when they don’t) but the over-all outcome is very, very positive in that;

  1. I don’t have to write lots of code to fake up binding.
  2. I can lean on a framework to provide a bunch of services – e.g. wiring up views and viewmodels.
  3. I can lean on controls like MvxGridView and MvxImageView and so-on to do a little bit more work for me and reduce the code I have to write.
  4. I can lean on plug-ins like the download cache to do work that pretty much every app is going to have to do and I get the benefit of those plug-ins being cross-platform.

Those are all big things but the main benefit that I see of MvvmCross isn’t one that I’ve taken advantage of here because in this scenario I’m really trying it out and seeing if I can use it only on Android to make up for the gaps between the code that I already had written and the platform.

The main benefit that I see here would be to use MvvmCross consistently for all of the implementations across all of the platforms. Clearly, it’s not needed in the XAML world in order to make bindings work but it can be used to provide a consistent set of built-in services;

  1. ViewModel location.
  2. Navigation.
  3. App lifecycle events & saving/restoring state.

and I know that if I’d started from that point of view I’d have had a simpler code-base and when I’d arrived at the Android platform my code would already be in a “shape” that would more easily have suited MvvmCross rather than me having to patch one or two things to fit in with the framework (not that this wasn’t possible).

One of the interesting things that I’ve found from this experiment is how similar MvvmCross feels to the PRISM framework for Windows Store apps and I’d love to see the PRISM guys expanding their platform reach to be more consistent across Windows 8.1 and Windows Phone but also maybe (just maybe?) branch out onto other app platforms like iOS and Android.

Until then, there’s MvvmCross Smile

Code for this post is here.


Posted Tue, Mar 11 2014 2:37 PM by mtaulty

Comments

Rehan Saeed wrote re: Baby Steps on Android with Xamarin–Part 5
on Tue, Mar 11 2014 4:27 PM

This is a great series of posts. I keep meaning to look into Xamarin but the cost is the only thing putting a spare time app developer like me off.

It would be interesting to see how you get in with converting your app to iOS too.

Prasad Honrao wrote re: Baby Steps on Android with Xamarin–Part 5
on Fri, Mar 14 2014 2:55 PM

Great article as always Mike. Thanks.

I completely agree with Rehan on the cost factor. I hope its on Microsoft's radar to get Xamarin within Visual Studio ( maybe in next VS release ?). This will boost confidence in .Net developer community as they can port their app across platforms easily.