Handling Lengthy Operations with Android App Widgets
Introduction
Android home screens enjoy the benefits of the App Widget framework, from displaying pictures to indicating the weather. In our previous articles on the App Widgets (listed in the reference section), we illustrated how to create a simple App Widget which allows for user interaction. Specifically, we built an App Widget that displayed a slideshow of images, where the slideshow controls were made available to the user. In these examples, the slideshow images were sourced locally from the device, but this is not terribly realistic for a real App Widget. Many developers will wish to have their App Widgets display information that is retrieved remotely, for example, from an RSS. Therefore, we now turn our attention to handling some "background processing" in conjunction with an App Widget. In this article, you will learn how to add background downloading of the images by using a Service object. To do this, we will build upon our previous App Widget example.
The following tasks need to be performed to add background processing to our existing App Widget:
- Create a new Service
- Modify the App Widget to call in to the
Service, as needed - Add code to the
Serviceto handle downloading of images - Add threading to the
Servicefor each on-screen widget
That's it in a nutshell. Each App Widget update (as handled in the onUpdate() method of the AppWidgetProvider) sends a message to the Service, starting it, as if it wasn't already started. This message must contain all the information needed to control a specific instance of the App Widget. The Service may already know about the App Widget, in which case it just updates it. Otherwise, the Service must launch a new thread to handle background downloading of the images for this particular App Widget instance. The instance is identified by the App Widget's appWidgetId value.
The Configuration screen has also been updated (see Figure 1). It now includes an entry for a URL to a compatible image feed. For this example, we use an Atom XML feed with image enclosures.

Figure 1: Updated Configuration screen with image feed setting.
Working with Android Services
Android services are loosely defined as background processes or executables that can be accessed from other applications. They can be started, to run in the background, or they can be directly connected to by means of a remote interface. However, an App Widget can't directly connect to a Service, no Broadcast receiver can. If you attempt to connect to a Service with an App Widget, an exception is thrown:
android.content.ReceiverCallNotAllowedException:
IntentReceiver components are not allowed to bind to services
To keep things simple, the primary interface to our Service will be via a mechanism we're already using: the SharedPreferences object. A Service can be started any number of times. However, only a single stop request is needed to shut it down. When starting the Service, we'll use Intent data to communicate what appWidgetId (App Widget instance) is starting up. This way, we can track all displayed widgets using just a single Service.
Starting the Service--or sending an update to it--is as easy as creating and posting an Intent. The following code demonstrates how to do this, including passing some control information to the Service:
Intent intent = new Intent(context, WidgetService.class); intent.putExtra(WidgetService.EXTRA_FLAG_REQUEST_STOP, requestStop); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId); intent.putExtra(WidgetService.EXTRA_FLAG_UPDATE_IMAGE, updateImage); context.startService(intent);
Although the method call to send this Intent is called startService(), it only starts the Service if it's not already running. There is no internal reference counting. A single call to stop the Service will stop it, regardless of how many times the startService() method is called. Since we may have multiple App Widgets using the Service, we've added a requestStop flag to specifically stop the thread for a particular instance of our App Widget.
On the Service-side of the startService() call is our onStart() handler. In short, the handler checks to see if a thread is already running for the specific App Widget instance. If not, one is started. If one is already running, the handler either stops it (if requestStop is true) or updates the image (if updateImage is true). Additionally, it updates the image in case the UI state has changed. The App Widget image updates proceed as they did in the previous examples, with the exception that the images are being pushed out from the Service. Here's some pseudo-code (edited for clarity; see code download for details) for this process:
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
int appWidgetId = intent.getIntExtra(
AppWidgetManager.EXTRA_APPWIDGET_ID, -1);
boolean updateImage = intent.getBooleanExtra(
WidgetService.EXTRA_FLAG_UPDATE_IMAGE, false);
boolean stopRequested = intent.getBooleanExtra(
WidgetService.EXTRA_FLAG_REQUEST_STOP, false);
if (threadPool.containsKey(appWidgetId)) {
UpdateThread thread = threadPool.get(appWidgetId);
imageUrl = getNextImageUrl();
updateWidget(this, appWidgetId, imageUrl);
} else {
UpdateThread thread = new UpdateThread(appWidgetId);
threadPool.put(appWidgetId, thread);
thread.start();
/* wait for first image to download */
imageUrl = getNextImgeUrl();
updateWidget(this, appWidgetId, imageUrl);
}
}
Although the details have been removed, the flow is relatively straightforward. The threadPool is simply a Hashtable to keep track of the thread for each App Widget instance. If the thread exists, we use it. If not, we start one and add it to the threadPool.
Downloading the Images within the Android Service
The UpdateThread, shown briefly in the
previous section, handles the downloading of the images from
the feed. All this thread does is wait around for a specific
amount of time to pass before downloading an XML file,
parsing it for images, then downloading those images--also
on a separate worker thread. The details around the XML
parsing and image downloading are up to the developer; any
method will work fine. The result, however, is important.
The images must be stored locally and a reference should be
kept in a Vector attached to the
UpdateThread. Vector objects are
synchronized for us, so we can use this to pass the image
references easily back to the main Service. This reference
is then used during an App Widget update to configure the
RemoteViews object.
Sidebar: Cautions
Although this article has illustrated how to allow for App Widgets requiring lengthy background operations using an Android Service, there are numerous housekeeping items to be aware of for production code that have not been addressed in our example. For example, when writing networking code, care should be taken to avoid excessive network data calls which could result in surprising bills to end-users. Busy background services should also do their best to avoid draining the battery of the handset. Additionally, the App Widget service should manage its resources prudently (e.g. by limiting its local storage requirements). For example, each image file could be resized before it's stored to reduce the disk space required by the App Widget. Along the same lines, the image files themselves should be persistently indexed to survive across handset resets. Many methods are available for handling these issues; however, the details of how are up to the developer and the specific App Widget implementation.
Summary
In this article, you've learned how to create a helper Service to handle background processing for an App Widget. In addition, this same Service is used to download the images the App Widgets will display in its slideshow.
References
Creating a Home Screen App Widget on AndroidHandling User Interaction with Android App Widgets
About the Authors
Shane Conder is a software developer focused on mobile and web technologies. He is currently working at a small mobile software company. With almost two decades of experience in software production, Lauren Darcey specializes in the development of commercial grade mobile applications. Recently, Shane and Lauren coauthored an in-depth programming book entitled Android Wireless Application Development, available from Addison-Wesley (ISBN: 0321627091). They are now working on an entry-level Android book, coming in Spring 2010. They can be reached at androidwirelessdev+a5@gmail.com and via their blog at http://androidbook .blogspot.com.
Partners
More for Developers
On the Forums
Visit the Forums »- 1 how to send mails from VC++ program without using outlook
- 2 Implementing Drag and Drop in TreeView
- 3 error PRJ0002 : Error result 31 returned from 'C:\Program Files\Microsoft Visual Stud
- 4 How can I Initialize getJdbcTemplate()?
- 5 socket bug System.Net.Sockets.OverlappedAsyncResult.CompletionPortCallback
