Archive for January, 2010

Android Dialog, or is it?

We’re all familiar with the concept of providing a temporary modal view to the user in an application for the purposes of notification or basic data entry. In the Android framework (as in many computer systems) a class is provided to the developer to create and maintain these views called a Dialog. This class is then further extended for you to make some convenient versions that allow entry of date/time information and make basic list selections (AlertDialog, TimePickerDialog, etc.). These classes work really well, and I would encourage you to leverage them whenever possible.

But what if you want to use the Dialog interface, but you have some custom data entry needs? Android makes it pretty simple to extend the base Dialog class and create custom behavior with a custom layout, and many people would consider this as the next logical option if they can’t solve their problem with one of the canned Dialog solutions. I’m here to tell you today that there is a better way.

The Problem

There are some subtle, but fairly major issues with the custom Dialog classes and state persistence. By design, the Dialog does not have the same functionality available to it as the Activity for life-cycle management. In particular, this includes managing device orientation changes, which (by default) completely breaks down the Activity and rebuilds it for a new configuration in Android. This is exacerbated by the realization that, in many Android devices, rotation is required EXTREMELY often after an entry dialog is shown because the user will want access to the keyboard to enter the data! If you’re dialog doesn’t rotate, your app is broken to the user.

So what’s the issue?  Do some experimentation with this and monitor LogCat some day.  As soon as you do an orientation change with an active dialog, you will get an android.View.WindowLeaked exception from the WindowManager.  This occurs (usually) because of reference conflict between the new activity that gets created, and a reference existing to the previous version of the dialog when you try to show it again.  This is actually pretty difficult to manage, even with managed dialogs using the Activity (although, here’s a hint: dismissing a dialog and destroying it are not the same thing). The canned dialogs available in the framework do not have this problem, which is why I mentioned using them whenever it fits.

The other “problem” with this implementation is that the Dialog class doesn’t get a passed Bundle or other framework inside of which to persist data (like anything the user STARTED to do before they rotated) like the Activity does.  This means a lot of passing data back to the calling Activity so it can manage the persisted data.

…This is all doable, but inefficient.

The Solution

Short Answer: The Dialog Theme for the Activity class.  Personally, the only thing that I REALLY like about the dialog class itself is the presentation method.  I like how it partially covers and dims the current activity which, conceptually, links it to the Activity in the user’s mind.  But everything else on the back end is MUCH better handled with an Activity:

  • startActivityForResult() and finish() are simple replacements for showDialog() and dismiss()
  • Data can be passed to and from the modal session using Intents (a great habit to get into anyway)
  • All the state persistence exists in the framework to handle rotation, like onSaveInstanceState() and the passed Bundle

Plus, creating an Activity class isn’t any more work than a custom Dialog.  Both are going to need the Constructor ( or onCreate() ) to call up super and then set the view to a custom XML layout file to set themselves up.

So the only missing piece is the Theme.  The one extra thing that you must do when you create an Activity instead of a Dialog is you must declare it in your Manifest so the system knows it exists when it comes to things like Intent resolution.  Coincidentally, the Manifest is also where you would set the dialog theme.  Take a look at the example below:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    ...>
    <application>
        <activity android:name=".HomeActivity">...</activity>
        <activity android:name=".NiceDialog"
                     android:theme="@android:style/Theme.Dialog">...</activity>
        ...
    </application>
    ...
</manifest>

Here, the Activity NiceDialog has been skinned to look just like a dialog would using the theme attribute. It now will wrap the content tightly and only partially cover the view of the calling Activity. Now the user is none the wiser, and you get all the benefits of Activity life-cycle management from your custom Dialog.

Editorial: Why Android Deserves Your Attention

I’ve read an increasing number of articles on the web recently from people who fervently believe that the Android platform is dead before it ever really got started. The common mantra going along with this is that Android is late to the party, and they didn’t bring anything new with them. First of all, I’m not sure how anyone getting into the game at this stage could be considered late, as the smartphone market is still quite infantile and rapidly developing…but I digress. Personally, I am very surprised by this perception, and have to wonder why the (mainly) iPhone community is so quick to attack?

I am a daily user of both the iPhone and Android platforms, and develop applications on both platforms as well. There are things about both that I love, and there are things about both that I hate; both as a user and developer.  I’m not the expert, and this is not an exhaustive comparison, but here are reasons that I believe Android deserves your attention (“you” being the developer) and why it is not dead…even if it doesn’t doesn’t immediately become king.

For context, as I’m writing this the latest software versions in the market are Android 2.1 and iPhone 3.1.2

The User Experience

There are some feature that Android provides to the user that the iPhone will need to incorporate eventually, in my opinion.  And I’m discussing them from a user perspective (not technical discussions of memory management, code efficiency, etc.)

  • Customizing Home Screen (Widgets)
    • The mobile user has severe A.D.D.; myself included. The faster the relevant content arrives to me, the less annoyed I am at how long I had to wait.  Checking the basics, like the Top 10 on my To-Do list or my next upcoming appointment, should not require me to run each application individually.  With Android, that data can live on my home screen in the form of widgets, and I can view it all right on the desktop (background services help a lot with this also, but we’ll get there).  And the data is REAL, it is not an image file stored and plastered as wallpaper.
  • Activity Stacking
    • My brain (and my life) works a LOT like a stack.  Often, what I am working on currently has something pushed on top of it that requires attention.  When I am done with that higher priority item, I need to step right back to doing what I was beforehand.  The Android concept of working follows this paradigm very well.  If I’m working in an application and need to send a quick email, I can bring email up on top of my current activity and do what I need to do.  After I am done with the email, I can go back to my previous activity and it is uninterrupted.  The same holds true if I get interrupted by a text message or other priority notification, I can load this activity ON TOP of what I was doing.  The tag line here is that I don’t have to close my old thoughts to start a new thought.

The Developer Experience

From the developer perspective, Android offers some neat opportunities as well.

  • Background Processing (Services)
    • Last year, when Apple announced that Push technology would be available to the iPhone, there was an uproar of excitement.  Suddenly, applications could grab the user’s attention without the need for the application to be running.  Push technology definitely has it’s place, but I do not believe that it can ever truly replace a background service in all instances.  Sometimes, developing a complete back-end server application and connecting with the Apple service is just too much overhead to put in to a project that just needs a method of notifying the user or doing simple work in the background.  Mobile devices may be resource constrained compared to the desktop platform, but I shouldn’t be afraid to run a few concurrent processes locally.  Shoot, I can do that on an 8-bit microcontroller.
  • System Modularity (Intents)
    • Intents embody the concept of inter-process communication and make it easy to modularize a system.  This architecture brings up a neat realization: once your app is using these to talk to itself, it’s a very small leap before apps start talking to each other.  This can be especially useful if you embrace the design philosophy that mobile apps should not have too many jobs, and that they should do 1-2 tasks efficiently.  Using an architecture based around Intents, complex tasks are now possible, while still holding true to the simplicity of each individual application.  This also provides great flexibility into way of hooking up with the core applications on the device (like mail and contacts) as just another module to your system.

I love my iPhone, and I love developing iPhone applications.  There are a lot of things on both the user and developer front that I prefer about Apple and the iPhone SDK.  I’ve chosen not to delve into them because so many people already have.  Any of the articles that I mentioned in the beginning spend a great deal of time touting the iPhone’s better features, so I’m just going to acknowledge (and agree) that they exist.  While these features alone may not skyrocket Google and cripple Apple, I believe that they are definitely enough to point out that Android has brought some new tricks to the party, and you probably ought to take notice.  I believe that they ARE enough to keep Apple from crippling Google straight out of the gate.