20 April 2009

Introducing home screen widgets and the AppWidget framework

One exciting new feature in the Android 1.5 SDK is the AppWidget framework which allows developers to write "widgets" that people can drop onto their home screen and interact with. Widgets can provide a quick glimpse into full-featured apps, such as showing upcoming calendar events, or viewing details about a song playing in the background.

When widgets are dropped onto the home screen, they are given a reserved space to display custom content provided by your app. Users can also interact with your app through the widget, for example pausing or switching music tracks. If you have a background service, you can push widget updates on your own schedule, or the AppWidget framework provides an automatic update mechanism.

At a high level, each widget is a BroadcastReceiver paired with XML metadata describing the widget details. The AppWidget framework communicates with your widget through broadcast intents, such as when it requests an update. Widget updates are built and sent using RemoteViews which package up a layout and content to be shown on the home screen.

You can easily add widgets into your existing app, and in this article I'll walk through a quick example: writing a widget to show the Wiktionary "Word of the day." The full source code is available, but I'll point out the AppWidget-specific code in detail here.

First, you'll need some XML metadata to describe the widget, including the home screen area you'd like to reserve, an initial layout to show, and how often you'd like to be updated. The default Android home screen uses a cell-based layout, so it rounds your requested size up to the next-nearest cell size. This can be a little confusing, so here's a quick equation to help:

Minimum size in dip = (Number of cells * 74dip) - 2dip

In this example, we want our widget to be 2 cells wide and 1 cell tall, which means we should request a minimum size 146dip x 72dip. We're also going to request updates once per day, which is roughly every 86,400,000 milliseconds. Here's what our widget XML metadata looks like:

Finally, let's write the BroadcastReceiver code to actually handle AppWidget requests. To help widgets manage all of the various broadcast events, there is a helper class called AppWidgetProvider, which we'll use here. One very important thing to notice is that we're launching a background service to perform the actual update. This is because BroadcastReceivers are subject to the Application Not Responding (ANR) timer, which may prompt users to force close our app if it's taking too long. Making a web request might take several seconds, so we use the service to avoid any ANR timeouts.

And there you have it, a simple widget that will show the Wiktionary "Word of the day." When an update is requested, we read the online API and push the newest data to the surface. The AppWidget framework automatically requests updates from us as needed, such as when a new widget is inserted, and again each day to load the new "Word of the day."

Finally, some words of wisdom. Widgets are designed for longer-term content that doesn't update very often, and updating more frequently than every hour can quickly eat up battery and bandwidth. Consider updating as infrequently as possible, or letting your users pick a custom update frequency. For example, some people might want a stock ticker to update every 15 minutes, or maybe only four times a day. I'll be talking about additional strategies for saving battery life as part of a session I'm giving at Google I/O.

One last cool thing to mention is that the AppWidget framework is abstracted in both directions, meaning alternative home screens can also contain widgets. Your widgets can be inserted into any home screen that supports the AppWidget framework.

We've already written several widgets ourselves, such as the Calendar and Music widgets, but we're even more excited to see the widgets you'll write!