AnDevCon III

Had a really great time speaking at AnDevCon III, yesterday!  The audience was awesome and turned what I expected to be a 40 minute talk into 70+ minutes.

All the materials from the talk are on GitHub, here:

https://github.com/bmeike/AnDevCon.git

Advertisements

Singletons in Android

There was a surprisingly acrimonious discussion about this, in the Android Developer’s Google Group, recently. Apparently the topic can be confusing.

The issue is that developers occasionally find themselves in need of a singleton. As a pattern, I would say that use of singletons has pretty well been discredited (see, e.g., WhySingletonsAreControversial ). Still, in Android, in a muli-activity application, it is entirely likely that there will be shared data and the desire to store that shared data in some place that is accessible to all application activities.

The problem with Singletons is that they really don’t exist. An instance of some kind of state is only a singleton within some context. A “singleton” on your phone is, clearly, not the same as the instance of the same singleton on my phone. It is even possible that the instance of the singleton on my phone this morning isn’t the same as the instance that was there last night, before I rebooted the phone. This only becomes a problem if the number or lifespan of the singleton surprises someone.

Before Java 5, the typical definition of a singleton, in Java, looked like this:

public final class Singleton {
    private static final Singleton instance = new Singleton();
    public static Singleton getInstance() { return instance; }

    private Singleton() {}
    // ...
}

After Java 5, the recommended implementation of a singleton looked like this:

public enum Singleton {
    SINGLETON;

    // ....
}

The idea is that there is only a single instance of the definition of a class (or enum) so we make that single class instance hold and return the singleton instance of the class. There are tricky extensions of this — usually ways to make it initialize lazily — but this is the gist.

In the Java community, the surprises typically showed up in applications that used multiple ClassLoaders. ClassLoaders are the things that read class definitions from, usually, the file system, and convert them into running code. The surprise comes when a developer doesn’t realize that a class definition is unique per ClassLoader (an object of which they may never even have heard) not per application. The Tomcat application server, for instance, loads webapps (.war files) each in its own ClassLoader. If you make changes to an app and reload it, it gets loaded in a new ClassLoader. If the previous version of the application hasn’t terminated yet it is entirely possible to have two distinct copies of the “same” singleton, one in each ClassLoader. …and that’s surprising.

It is entirely possible to for the same thing to happen, in Android. Android’s similarity to Java absolutely extends to its definition of classes as unique per ClassLoader. Multiple ClassLoaders: multiple instances of your singleton. You can demonstrate this with an app of about 10 lines. At least at this point, though, most Android applications don’t make use of ClassLoader magic and so most developers aren’t getting this particular surprise.

When Android developers want a singleton — perhaps the DAO or a place to remember a running AsyncTask — they might consider keeping the reference to it in a custom subclass of Application. If you read the official documentation for the Application class, though, you’ll find this comment, barred for emphasis:

There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context which internally uses Context.getApplicationContext() when first constructing the singleton.

This is all fine, so far. But here comes a surprise. The Android OS may completely terminate your application and then recreate it. When the new process is created, your classes are loaded and initialized. Exactly how to describe this terminate/reload event was the source of significant heat in the Google Groups discussion. I’ll resist the urge to poke fun at the guys that insisted that this was not a suprise because the reload happens in a new process [The classes are not reloaded! Rather there is a new “process”. What is a “process”? It is an undetectable entity that makes it appear that your classes have been reloaded…] because they are exactly right. An Android application will, frequently, span several processes. This is not something that is common in, say, the desktop world. It may be surprising.

The point is that you cannot put program state into class data members and expect it to stay there. Frequently, this isn’t a problem. If you use a class data member to store a reference to something idempotent, e.g., your DAO, you don’t care which specific instance you happen to use. That is, this code works just fine:

public class MyApplication extends Application {
   private static final MyDAO db = new MyDAO();
   public static MyDAO getDB() { return db; }

   // ...
}

This code, however, won’t work:

public class MyApplication extends Application {
    private static long lastUpdate;
    public static void setLastUpdate(long udate) { lastUpdate = udate; }
    public static long getLastUpdate() { return lastUpdate; }

    // ...
}

… or, at least, you may be surprised to find that getLastUpdate returns 0, even though the code has called setLastUpdate() at some point. Suppose an Activity in the application looks like this:

// ...
setContentView(R.layout.main);
((TextView) findViewById(R.id.myText))
    .setText(String.valueOf(getLastUpdate()));
((Button) findViewById(R.id.myButton)).setOnClickListener(
    new Button.OnClickListener() {
        @Override public void onClick(View v) {
            MyApplication.setLastUpdate(System.currentTimeMillis());
        } } );
// ...

If I push the button, then the Home key and then run a bunch of other apps (on my Nexus S, about a dozen), when I return to this app, the text view will read 0, despite the fact that I definitely pushed the button.

I don’t think anyone is claiming that this is a bug. …and it certainly helps to understand why it happens. As my colleagues point out, it happens because the application survives process boundaries. It is definitely surprising, though, and it puts that quote from the documentation, cited above, in a new light.  Neither the application object nor a static singleton can be expected to hold persistent state for the life of the application! It just won’t work.

What might be a bug is that it is hard to tell when a process ends (thus my jibe about processes being undetectable). I have empirically determined that Application.onTerminate() is not always called, and I have from an authority I respect, that it is, actually, never called (documentation to the contrary). It is probably best to design so that you don’t depend on knowing, anyway. To do that, your static fields must appear to have a value that is constant as of creation. Making them final is a good start.

In some ways, this is the opposite of the problem in Tomcat.  Whereas, in affected web apps, a single object might, at some point in its lifetime, have references to multiple, inconsistent copies a given singleton, in Android a single object, over its lifetime, can’t get a reference to even one instance that stays consistent.  So, don’t be surprised.  It is really easy to create an application in which an Activity, for instance, retains some state for much longer than fields in the Application object, or its own static fields. Nothing new: we’ve all initialized apps from the file system or from a database, before. Usually, though, we do it at “startup” and we have some definite ideas about when “startup” happens.. That’s not how Android works. Serialize your state into a Bundle or Sqlite, if you need to keep it around.

Programmatic and Layout fragments

I finished a deep dive into the new Fragments feature in Honeycomb.  It’s an interesting feature — combining the UI of a View with the lifecycle of an Activity — and it has a few interesting complexities.

I’m getting a kick out of the two senses of the word “fragment” evident in articles like this one, that talk about the release of the ACL (Android Compatibility Library).  The ACL allows Android releases as far back as Donut to use fragments.  The point seems to be that back-fitting Fragments into older releases reduces Android’s perceived version fragmentation problem…

I came across one issue, using Fragments, that qualifies as a “gottcha”.  I don’t think I’d call it a bug but it certainly can be a surprise.

Consider the canonical fragment demo: an application that presents a list view and then a fragment that shows content based on the selection in the list.  You might imagine an RSS reader or a mail application, or something like that.  You might expect to set up a screen layout that looks something like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
            android:id="@+id/list"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    <fragment android:name="net.callmeike.android.example.FragmentationBomb"
            android:id="@+id/fragment"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2" />
</LinearLayout>

That seems like a perfectly reasonable approach, based on the documentation.  It’s a static definition for a page consisting of the list and the fragment that you want visible when your applications starts up.  Presuming this layout lives in a file named “main.xml”, you’d make it visible like this:

@Override
public void onCreate(Bundle state) {
   super.onCreate(state);
   setContentView(R.layout.main);
   // ...

There’s already something to be careful about.  The fragment class, net.callmeike.android.example.FragmentationBomb, will be instantiated during that call to setContentView.  That means that the fragment cannot count on there being a selection in the list from which it can determine the content it should display.  It had better be able to handle an empty selection.

There’s another issue, though that is much more subtile.  A key feature of a fragment is that it can be put on the back stack.  This is nice because it makes multi-pane applications navigate just like their single-pane cousins.  When using an Android app on a small screened device, a user navigates forward onto a new screen — perhaps by selecting something — but then pops back to the previous screen simply by pushing the back button.

On a device with a larger screen, an app like this one should behave analogously. If the user selects the second item in the list, then the fifth, and then pushes the back button, you’d hope that the screen looks exactly as it did when they originally selected the second item.  The back button should back out actions, exactly as it does on a small screen (or in a web browser, for that matter).

Fragment transactions enable exactly that behavior:

FragmentTransaction xact = getFragmentManager().beginTransaction();
xact.replace(R.id.fragment, FragmentationBomb.newInstance(selection));
xact.addToBackStack(null);
xact.commit();

This bit of code puts the current fragment on the back stack and replaces it with a new fragment instance — presumably based on a new selection in the list view.  When the user pushes the back button, the back stack is popped and the previous list selection and the fragment that contains its contents are restored.  Perfect!

Well, almost.  An application implemented as described above will fail and crash with a fairly inscrutable message like this:

java.lang.IllegalStateException: Fragment did not create a view.
    at android.app.Activity.onCreateView(Activity.java:4095)

It turns out that fragments created in a layout and fragments created programmatically are very different animals and have very different lifecycles.  Replacing one with the other is bound to cause failures.  You can drive the bug by running the transaction code, once, so that there is a programmatically created fragment visible, and then rotating the screen from portrait to landscape.

A fragment that is created as part of a layout has its onCreateView method called when it leaves the Fragment.INITIALIZING state.  If the fragment is created programmatically its onCreateView method isn’t called until it leaves the Fragment.CREATED state.  When Activity.onCreate is called, the fragment is still in the Fragment.CREATED state: it’s onCreateView method has not been called and it has no view.  The moral appears to be: “Never mix layout and programmatic fragments”.

While the code could be changed so that the layout fragment reloads its content when the list view selection changes, that defeats the whole point of the fragment transaction: the back stack.  A better solution uses only programmatically created fragments.  Use a layout like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   <ListView
            android:id="@+id/list"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1" />
    <FrameLayout
            android:id="@+id/fragment"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="2" />
</LinearLayout>

…and create all of your fragments programmatically,  installing them in the view like this:

FragmentManager fragMgr = getFragmentManager();
FragmentTransaction xact = fragMgr.beginTransaction();
if (null == fragMgr.findFragmentByTag(FRAG_TAG)) {
    xact.add(R.id.fragment, FragmentationBomb.newInstance(selection), FRAG_TAG);
}

The fragment will be occupy the space created for it by the FrameLayout item.  The FRAG_TAG is just a unique identifier to make sure you don’t add that fragment more than once.  Once you’ve tagged the fragment in the layout, you can recover that exact fragment with the findFragmentByTag call.  If the fragment already exists, adding it again would leak fragments.  Using the tag guarantees that you will only create add the fragment once and can subsequently replace it.

It turns out that there’s a really slick way to handle multiple devices, using layouts and fragments.  I’ll describe that later.

AIDL and Fragments

Catherine is out of town, so it’s just me and the cat.  I’m trying to catch up on Fragments, AIDL and the Android Security model.

AIDL bumps into some serious problems when combined with design for inheritance.  I think the best idea is an abstract base class whose unmarshaller, the reference stored in the public CREATOR member, is a factory for all of the subtypes.

I suppose you could do it like JDBC did: each subclass registers, in a static initializer, with the base class.  Nah… that’s a bad idea.

“Master” building on Ubuntu and Mac

Yesterday I got the “master” branch of Android to build on both an Ubuntu 10.10 and on Snow Leopard.  I don’t know if I can build Froyo and earlier, on either.  Apparently it depends on Java 5.  It’s a low priority experiment, anyway.

The Ubuntu build was completely straight-forward, once I installed the 64-bit OS.  To my surprise, I was able to install all of the apps I normally use, including Skype!  Linux gets better and better, every time I look at it.  I frequently find myself repeating the ancient incantations that used to be necessary to get things working (/etc/init.d/smb restart), only to find that they’ve been replaced by perfectly civilized and functional UIs.

I still haven’t figured out how to drag windows between workspaces.

The Snow Leopard build was only slightly more complicated: it failed on a device out of space error.  The Google Doc says that 8G is sufficient.  Maybe back when the docs were written.  The full build occupies 10G of the 13G case-sensitive disk image I built for it.

Today is for studying AIDL

Building Android

The big task for this week is building Android from scratch.  The Google docs imply that it is now possible to build it on a Mac, although I’ve not had any luck so far.  Make fails with:

target Java: core (out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes)
libcore/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/HttpURLConnection.java:52: cannot find symbol
symbol  : class Msglocation: package org.apache.harmony.luni.util
import org.apache.harmony.luni.util.Msg;

The machine on which I used to do builds — an Ubuntu 10.10 install — no longer works, either.  Apparently Android will no longer compile on a 32-bit install.  Also, apparently, there’s no simple upgrade path from a 32-bit install to a 64-bit install.