/ XAMARIN

Xamarin and Android – Specific Solutions to Specific Problems #1

At our company, I am the soul that has been tasked with doing our Android development. We have chosen to use Xamarin for this and as I race up the learning curve, I thought it pertinent to start blogging the solutions to any problems I encounter along the way. Welcome to my “Specific Solutions to Specific Problems” series…

 

1. I have a ListView and the layout being inflated for each row contains a ToggleButton as well as TextView elements. The ItemClick and the background selector don’t activate while the ToggleButton is in the layout. If I remove the ToggleButton everything works fine.

It seems when there are other clickable elements in the row layout the ItemClick stops firing. In addition if you have any selectors changing the background they will also not work. After some exhaustive searching I found the answer here. If I set the following properties on any clickable elements in the row layout the text in the row will now properly use the selector and fire the ItemClick event:

[syntax type=”html php js css”]

android:focusable=”false”

android:focusableInTouchMode=”false”

[/syntax]

 

2. I want to start an activity and return a result to the calling activity. I use StartActivityWithResult to do this but when I override OnBackPressed on the called acitvity, none of the data in the intent gets passed back to the caller.

In the activity that I started with StartActivityWithResult, I have overridden OnBackPressed to pass back some information:

[syntax type=”html php js css”]

public override void OnBackPressed()

{

base.OnBackPressed();

Intent intent = new Intent();

intent.PutExtra(“UserMessage”, editText.Text);

SetResult(Result.Ok, intent);

}

[/syntax]

In the calling activity I have the following callback defined:

[syntax type=”html php js css”]

protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)

{

base.OnActivityResult(requestCode, resultCode, data);

if (data != null && data.HasExtra(“UserMessage”))

{

string message = data.GetStringExtra(“UserMessage”);

}

}

[/syntax]

As I discovered here, the problem is with the base.OnBackPressed call. The following explanation sums it up nicely:

[blockquote source=”user658042 on Stack Overflow”]Thats the default implementation of onBackPressed() (also mentioned in the documentation). This means your activity gets finished (with the default code RESULT_CANCELLED) before your other code gets invoked. Removing super.onBackPressed() and adding finish() on the bottom should fix this.[/blockquote]

It does indeed. I changed the OnBackPressed override to look like this and I now get a response code of RESULT_OK and an intent with the data I wish to return:

[syntax type=”html php js css”]

public override void OnBackPressed()

{

Intent intent = new Intent();

intent.PutExtra(“UserMessage”, editText.Text);

SetResult(Result.Ok, intent);

Finish();

}

[/syntax]

 

3. I want to use an IoC container to manage my dependencies throughout my Android application. The problem is that I have heard that static variables are bad news in Android and that’s where I’ll want to store my IoC container. What are my options here?

I love Inversion of Control and dependency injection. The goal is to achieve separation of concerns within the software I write but at its simplest there’s nothing like a mock service layer for really productive development. I like to write an interface for my service layer and then implement both a real service layer and a mock layer that returns sample data. That way I can develop my user interface against the mock layer and simply switch to the real layer when I have completed most of the user interface. Read all about these topics here if you need more clarification.

I went searching for IoC frameworks for Xamarin and this was basically the short list:

The best resource 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 advice on how to glue it all together.

The main issue for me was the use of statics. Other Android developers had warned me that the operating system can kill your activities and even the entire process if it needs to reclaim memory. Usually you would configure your IoC container in the first activity and then use the static reference throughout the application. If the system does kill the process it will be restarted again at that activity but now without the static IoC container. This is a problem.

I had to figure out a place that I could do this scaffolding before any activites actually start. That’s when I came across this bad boy. This statement in particular clarified things for me:

 

[blockquote source=”Mark on Stack Overflow”]

Be careful when using static variables. Don’t think that when you initialized them in activity 1 – you will have them initialized in activity 2. The only safe place to initialize global statics would be Application class.

 

[/blockquote]

 

Mark also suggested using DDMS to simulate this scenario. I followed the instructions and killed the process after startup. As predicted, the activity that was resumed attempted to use the IoC container to get the service layer and promptly threw all of its toys out of the cot. If I instead subclassed Application and did the setup there, I could always ensure the dependencies were configured whenever the process started:

[syntax type=”html php js css”]using System;

using Android.App;

using Android.Runtime;

using SomeApplication.Common.Services;

namespace SomeApplication.Android

{

[Application(Debuggable = true, Icon = “@drawable/AppIcon”, Label = “My Application”)]

class MyApplication : Application

{

public MyApplication(IntPtr ptr, JniHandleOwnership ownership) : base(ptr, ownership)

{

}

public override void OnCreate()

{

base.OnCreate();

#if DEBUG

ServiceFactory.Initialize(ServiceFactoryType.Mock);

#else

ServiceFactory.Initialize(ServiceFactoryType.Service);

#endif

}

}

}[/syntax]

As Greg mentioned in his post this is the preferred strategy for making sure all of your dependencies are configured at application start.