Writing an Android Widget: What the docs don't tell you

Having recently written my first Widget for Android, here are some of the things I learned in the process.

Use a thread, not just a service

In the blog post introducing the AppWidget framework, you are encouraged to use a service to perform your widget updates if you are doing anything that might take a little longer, in order to avoid Application Not Responding (ANR) timeouts. However, this will usually not be enough. Since your service callbacks also run in your application's main thread, you'll still be in danger of triggering ANR as soon as your process is asked to do other things while still being busy with your first widget update. For example, your widget's broadcast receiver might be triggered again for another instance of your widget, or the user might start interacting.

The solution is to have your service start a separate thread. For an example, see Jeffrey Sharkey's android-sky Widget.

Stop your service when you're done

When your done with updating (if your using a thread, it'll be when your thread has finished), make sure you stop your service. Nobody seems to be doing this, including the example code in the official blog post, nor sample projects by Android team members. As a result, so many widgets have their process run in the background all the time, not allowing Android to kill it to reclaim memory. Considering that RAM isn't exactly a plentiful resource on devices like the G1, I would have thought this were especially important. Unless your updating multiple times an hour, I would strongly suggest that stopping your service and letting Android free up your process when necessary is the right thing to do.

Try to work around the bugs in Android 1.5 and the Launcher's Widget implementation

It turns out there are quite a few of them, and they all seem to revolve around issues with deleting a widget. In particular:

  • AppWidgetProvider fails to handle delete intents correctly. As a result, if you are subclassing it, your onDelete() method will not be called. The solution is to override onReceive() and handling delete intents yourself. Here's a code snippet.
  • In any case, if a user deletes an instance of your widget, the 1.5 default home screen will still keep sending update requests for the already deleted widget's id, until the user adds a new instance of your widget (apparently, some internal bundle of widget ids is not reset on delete). This seems like this could result in a considerable waste of resources, or even impact your functionality, with you sending out widget updates that nobody is going to see. Note: I'm not sure if those obsolete widget ids are cleared out on reboot (probably). You might also not have this problem if you're using custom scheduling instead of the default update facility.
    The best one can do here appears to be keeping an internal list of deleted widgets (widgets for which you - hopefully - received a delete intent), and then just skipping those updates.
  • Finally, there seems to be another issue with phantom widgets when a configure activity is used and the user cancels it. In this case also, you'll continue to receive updates for the widget (which won't be shown anywhere), except it seems even worse, because apparently this time around, widget will really exist internally, rather than just some internal state not being update correctly (so even a reboot won't help here).
    The work around seems similar: keep information around that indicates whether a widget as been configured successfully, and don't bother updating widgets that haven't.

2009-07-18: It appears there is another widget bug.

4 Responses to “Writing an Android Widget: What the docs don't tell you”

  1. Brindy Says:

    Useful information. Thanks.

  2. Wilder Prozess ? - Android-Hilfe.de Says:

    [...] [...]

  3. Tom Says:

    Nice blog. These are absolutely things to look out for when writing AppWidgets!

    But, the fact that you have to spawn threads when using a service is something that the documentation DOES tells you:

    "Like activities and the other components, services run in the main thread of the application process. So that they won't block other components or the user interface, they often spawn another thread for time-consuming tasks (like music playback)." (http://developer.android.com/guide/topics/fundamentals.html)

    Also, the onDelete() bug is in the documentation:

    "Note: In Android 1.5, there is a known issue in which the onDeleted() method will not be called when it should be. To work around this issue, you can implement onReceive() as described in this Group post to receive the onDeleted() callback."
    (http://developer.android.com/guide/topics/appwidgets/index.html)

    Just for the record ;)

  4. Androidhk.com» Blog Archive » Android Widget Bugs (-.-) Says:

    [...] 整理的Widget Bug List. This entry was written by bitartist and posted on 十月 13, 2009 at 6:37 下午 and filed [...]

Leave a Reply