You are on page 1of 10

One often vaunted feature of Android are the Home screen widgets.

The official definition of


a widget, taken from the Android documentation is:
App Widgets are miniature application views that can be embedded in other applications
(such as the Home screen) and receive periodic updates.
In practice, widgets are generally only used on the Home screen. Widgets can also be
interacted with, reacting to touch events, although there are some limits on what can be
done. In this article, I will show you how to write a simple widget that shows the current time,
and loads up your app when you click on it. In future articles, we will add additional
functionality to show graphics, update frequently, and fetch data to show from the internet.
Androids documentation of App Widgets provides a pretty good starting point when learning
widgets. We will start with an example that is very similar to their tutorial, then we will move
on to demonstrate some more advanced features. We assume that the user is using Eclipse
with the Android Development Extensions to produce their app, but the same results can be
achieved in other IDEs. Getting Started with Android is a no nonsense guide to setting up
an Android development environment.
Lets start by creating a new Android Project. Select File New Android Project. Fill in the
wizard as you see fit with some sensible values. You can choose whatever values you like,
but for my example I used the following values specifically, leaving the other values to their
defaults.

Project Name: Widget Example

Build Target: 2.2 [API Level 8]

Application Name: Widget Example

Package Name: com.eightbitcloud.example.widget

Figure 1

Then click on Finish. This will create you a fully working and testable Android application.
Run it in the emulator now if you like, by right clicking on the project and selecting Run As
Android Application. You might need to create a definition for an emulator. Once running,

the app simply displays you a black screen with a Hello World string in it. Boring, but it is a
good starting point.
In Android, all components that are shown in the OS are defined in the manifest file. Load
upAndroidManifest.xml from the top level of your project. Eclipse will show you the file in a
structured editor, but if you are familiar with XML, it might be easier to switch to the source
view by selecting the last tab in the editor. It should look something like this:
1 <?xml version="1.0" encoding="utf-8"?>
2 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
4
5
6

package="com.eightbitcloud.example.widget" android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="8" />
<application android:icon="@drawable/icon" android:label="@string/app_name"
>

7
8
9
10
11
12
13
14
15

<activity android:name=".WidgetExampleActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

The important thing that is in this file at the moment is the Activity that specifies the main
view of the application. Youll see it inside the application tag. This tells Android where the
class is that specifies the main view of your application, what name it should be given (by
the label attribute), and what intents it should respond to. The main view is marked as
the MAIN action to indicate that Android should load it up when the app starts, and
with LAUNCHER to indicate that it should appear in the application list. None of this is
directly related to widgets, but is useful background on how Android handles its manifest.
To add our widget, we need to introduce a new element to the manifest that specifies it.
Below the activity, add the following
1 <receiver android:name=".ExampleAppWidgetProvider" android:label="8-bit cloud
widget 1">
2
<intent-filter>
3
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
4
</intent-filter>
<meta-data android:name="android.appwidget.provider"android:resource="@xml
/widget1_info" />
6 </receiver>
5

This specifies a new class ExampleAppWidgetProvider which will be responsible for


receivingAPPWIDGET_UPDATE intents. We need to give a name to our widget, which we do

by specifying a value for theandroid:label attribute. Normally, you would specify this in your
applications res/values/strings.xmlfile, but for the sake of simplicity I have placed the value
directly in the manifest file. I used 8-bit cloud widget 1. The remainder of the configuration
of the widget will be specified in the meta-data file, which will be located in
the res/xml/widget1_info.xml file. Our next step is to create that meta-data file. Create it by
selecting File New Other Android Android XML and fill it in as follows.

Figure 2

Once the file is created, switch to the source tab, and set the contents of the file to the
following:
1 <?xml version="1.0" encoding="utf-8"?>
2 <appwidget-provider xmlns:android=
"http://schemas.android.com/apk/res/android"
3
android:minWidth="294dp"
4
android:minHeight="72dp"
5
android:updatePeriodMillis="1000"
6
android:initialLayout="@layout/widget1">
7
</appwidget-provider>

The minWidth and minHeight parameters specify the size of the widget. There are special
rules about the sizes that Android widgets can have because Android arranges its home
screens in a grid of 4 x 4. The documentation specifies that you calculate the size by using
the following formula:
size = (number of cells * 74) 2
In our example, we want our widget to be 4 * 1 cells in size, so we specify the size as (4 *
74) 2 = 294 by 72 dps.
Android views only update on a periodic basis. We want to display a clock, so Ive put in
anupdatePeriodMillis of one second (1000 ms), so that it updates every second. It turns out
that values this small dont work, but Ill come back to that later. Finally, we specify what
layout will be used for the widget. Lets create that layout file using the same android XML
creation wizard we used before, except this time we select a layout type and a file name of
widget1. As before, switch to the source tab of the file, and use the following contents:
1
2
3
4
5
6
7
8
9

<?xml version="1.0" encoding="utf-8"?>


<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:layout_margin="4dp"
android:background="@drawable/background">

<TextView android:id="@+id/widget1label"android:layout_height="wrap_cont
1
0 ent" android:textAppearance="?android:attr/textAppearanceLarge" android:layou
t_width="wrap_content"/>
<Button android:text="Click
1
1 Me!" android:id="@+id/button"android:layout_width="wrap_content" android:lay
out_height="wrap_content"/>
12 </LinearLayout>

The layout specifies what components will be in the widget, and how they are laid out. The
important things to see here however are the TextView and Button components that have
been added to it. They correspond to the components that will be shown on the screen.
When creating your widget, you might be tempted to create fancy layouts, using your own
custom components and complex layouts. There are quite severe restrictions on which
components can be used in Widgets however, because the widget runs in a different
application, and doesnt have access to your own code when rendering.
There are sneaky ways you can make your widget look like its more complex however,
which I will cover in another article. For now, note that the only components that you can
use in a widget are:

FrameLayout

LinearLayout

RelativeLayout

AnalogClock

Button

Chronometer

ImageButton

ImageView

ProgressBar

TextView

ViewFlipper
Youll notice in the layout that there is a background specified for the widget as well. Youll
need to create your own background drawable in res/drawable/background, or you could
use the one I created for the example.
1

package com.eightbitcloud.example.widget;

import java.text.DateFormat;

import java.text.SimpleDateFormat;

import java.util.Arrays;

import java.util.Date;

import android.app.PendingIntent;

import android.appwidget.AppWidgetManager;

import android.appwidget.AppWidgetProvider;

import android.content.Context;

10

import android.content.Intent;

11
12

import android.util.Log;

import android.widget.RemoteViews;
13 public class ExampleAppWidgetProvider extends AppWidgetProvider {
14
DateFormat df = new SimpleDateFormat("hh:mm:ss");

15
16

public void onUpdate(Context context, AppWidgetManager


appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;

Log.i("ExampleWidget", "Updating widgets " +


Arrays.asList(appWidgetIds));
18
// Perform this loop procedure for each App Widget that belongs to this
19
// provider
20
for (int i = 0; i < N; i++) {
17

21
22
23

int appWidgetId = appWidgetIds[i];


// Create an Intent to launch ExampleActivity

Intent intent = new Intent(context, WidgetExampleActivity.class);


PendingIntent pendingIntent = PendingIntent.getActivity(context, 0,
24
intent, 0);
25
// Get the layout for the App Widget and attach an on-click listener
26
// to the button
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.widget1);
28
views.setOnClickPendingIntent(R.id.button, pendingIntent);
29
// To update a label
30
views.setTextViewText(R.id.widget1label, df.format(new Date()));
31
// Tell the AppWidgetManager to perform an update on the current app
32
// widget
33
appWidgetManager.updateAppWidget(appWidgetId, views);
34
}
35
}
36
}
27

This class contains the code that will be used to update our view each time that the timeout
period expires. It is responsible for updating the contents of the widget. Widgets run in a
different application (the Home screen) to our application, so it is not just a matter of simply
updating the components. Instead, you are given access to a RemoteViews component
which you can use to set strings, images and button actions on the remote components.
In our case, we are looking to do two things. First, we want to add an action listener for our
button so that when we click on it, it opens up our main application. This is done with
the PendingIntent and thesetOnClickPendingIntent() method. Second, we want to update
the TextView in our view to show the current date. This is done via the call
to setTextViewText(). Once this is done, we update the widget using
the updateAppWidget() method.
Voila! We now have a working widget application. Install it on your emulator by selecting the
run profile you created before. As before, it will show you the application view. Quit out to
the Home screen using the home button, then long press on the background and
select Widget. You should now be presented with a list of widgets, with your widget in the
list. Select your widget, and it will be added to your home screen.

Figure 3

Figure 4

Yay! Hang on, the clock isnt updating! We set the update period to 1 second in our metadata file, so it should update once every second, right? It turns out there is a very good
reason for this. Every time a widget needs updating, Android will wake up your device, load
your application, and run the WidgetProvider class to update the widget. It does this even if
your screen is off and the phone is asleep. If the update period were set to only run a few
times an hour or less frequently, then this doesnt amount to much of a battery drain. If the

update period is very short like our example, then the widget would drain very quickly and
you would have a long list of angry customers. To avoid this, Google limits the update period
to once every half an hour or greater.
Luckily there is another way to handle more frequent updates; one that only operates while
the screen is on so as not to drain the battery. To do this, we use the AlarmManager. Using
the AlarmManager will be the focus of my next article.
As with all my articles, I have posted the source to GitHub. You can find the code as part of
my Android-Examples repository, in the WidgetExample subdirectory. This project will be
updated as the tutorial series progresses, so I have marked this first example as a tag.
Please feel free to ask questions or provide feedback

You might also like