Be Careful With Static Stuff on AsyncTask

I was writing a sample app to run on the WIMM One wearable Android device, and I ran into a strange error. The flow was:

  • Run an activity, which detected that we had no data, raised a dialog, and finished once the dialog closed.

  • Along the way, the activity sent a command to an IntentService to go get the data.

  • The next time you would launch the activity, you would get a warning about “sending message to a Handler on a dead thread”, and the activity would not fully start.

I, being a bit cocky, assumed that the problem was something with the WIMM environment.

Ummmm… not so much. I screwed up. In fact, I had seen reference to this problem before, but never fully appreciated what it meant until I ran into it myself.

The problem was that the load-the-data logic for the activity was using an AsyncTask. That, on its own, is not a problem — in fact, it’s desirable (particularly on environments where you can’t use loaders).

However, AsyncTask has static data members. And one of the limitations of those static data members is that they need to be initialized on the main application thread.

Normally, this is not a problem, as you usually only reference the AsyncTask class on the main application thread, when you go to create your first instance of the task to execute.

In my case, though, I had moved some common logic into a static method on my AsyncTask subclass… and I was calling that static method from the IntentService in onHandleIntent(). That was the first time I referenced my AsyncTask subclass, and it was on a background thread. That initialized a static Handler used by AsyncTask on the background thread, not the main application thread.

The error message was pointing out that the AsyncTask static Handler was associated with a thread (the one from onHandleIntent()), which was now dead.

The solution: simply move the static method elsewhere.

The moral of this story is to be very careful about when you first use AsyncTask. Some people have resorted to using a custom Application object and touching an AsyncTask subclass in onCreate(), just to make sure that it is properly initialized. While IMHO that is not necessary, you do have to pay attention.

Many thanks to the WIMM team for pointing out my error. You can find out more about this issue on the Android issue tracker.

Find out about new posts on the CommonsBlog via the Atom feed, or follow @CommonsWare on Twitter!