Sunday, 9 June 2013

SherlockActivity and AlertDialog Don't Work Together

I decided to refresh my knowledge of Android by porting one of my iOS apps while using all the new features of Android 4.* I might find useful. Knowing that Android documentation isn't always reliable, I selected as my guide the most up-to-date version of The Busy Coder's Guide to Android Development (I will refer to it as BCG further on). I used to rely on this book's predecessors in the past, they were quite good.

There is a catch with Android: many desirable new features were introduced to it starting from version 4, Ice Cream Sandwich, which was introduced in October 2011, more than a year and a half ago. However, as of the beginning of June 2013 there are still more than 40% of devices out there using the older, pre-4.0 versions of Android.

This is really a pain, because every developer would like to use the new advanced features of Android, but doing that he will lose 40% of the potential audience, which is clearly not acceptable.

Google made some effort to help us and provided a compatibility library with backports of many of the new features to the earlier versions of the platform. However, on some reason that library doesn't offer any solution for the ActionBar, while most developers these days would wish to use the ActionBar, and they would want their app to look consistently across all the different versions of Android.

Thankfully, a third-party library ActionBarSherlock addresses the problem, and it is well implemented and reliable, so everyone I know in the Android development world uses it.

Quite naturally, BCG recommends the AndroidBarSherlock and uses it in most examples. And that's fine. I followed the advice and now all the activities in my new app are SherlockActivities.

Everything was great until I needed an AlertDialog. I looked into BCG, and it recommends to use "the modern way to display the dialog" by using a DialogFragment. So I did that, created an implementation of the DialogFragment, and since I am targeting pre-ICS versions of the platform, I used the support library version of the fragments (android.support.v4.app.DialogFragment).

Everything went smoothly until I tried to display my new dialog. The incantation for that is
new SampleDialogFragment().show(getSupportFragmentManager(), "sample");

Unfortunately, my SherlockActivity had no idea how to get a fragment manager from a Google support library. And naturally, Google pretends that it has no idea of the ActionBarSherlock. So DialogFragment simply doesn't mix with ActionBarSherlock.

I checked the Android documentation, and it is all about the DialogFragment, as if other options never existed at all. Which is understandable, they did provide a backport of fragments for the older platforms, and the DialogFragment solution does offer some benefits compared to the old way in the situation when the device is rotated. Well, in the ideal world either the support library would offer an ActionBar backport, or everyone would be using Android 4.* by now. But in the real world we have to use ActionBarSherlock for now.

What unpleasantly surprised me though is that Mark Murphy, who in his BCG almost insists on using ActionBarSherlock, follows Google in offering only the DialogFragment solution, without even hinting that you have no way to use it with ActionBarSherlock.

Anyway, here is the solution. I had to dig it out from my old code, written more than three years ago:

AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(getString(R.string.title))
.setMessage(getString(R.string.message))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() 
{
    @Override
    public void onClick(DialogInterface dialog, int which) 
    {
     // Handle positive button    
    }
})
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() 
{
    @Override
    public void onClick(DialogInterface dialog, int which) 
    {
        // Handle negative button
    }
}).show();