How To Code an Android Widget

Tweet

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.

Android’s 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
Android Widget Figure 1

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 up AndroidManifest.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:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
  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">
    <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. You’ll 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

<receiver android:name=".ExampleAppWidgetProvider" android:label="8-bit cloud widget 1">
  <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
  </intent-filter>
  <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget1_info" />
</receiver>

This specifies a new class ExampleAppWidgetProvider which will be responsible for receiving APPWIDGET_UPDATE intents. We need to give a name to our widget, which we do by specifying a value for the android:label attribute. Normally, you would specify this in your application’s res/values/strings.xml file, 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.

Android Widget Figure 2

Figure 2

Once the file is created, switch to the source tab, and set the contents of the file to the following:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="294dp"
    android:minHeight="72dp"
    android:updatePeriodMillis="1000"
    android:initialLayout="@layout/widget1">
</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 I’ve put in an updatePeriodMillis of one second (1000 ms), so that it updates every second. It turns out that values this small don’t work, but I’ll 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:

<?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_content" android:textAppearance="?android:attr/textAppearanceLarge" android:layout_width="wrap_content"/>
    <Button android:text="Click Me!" android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content"/>

</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 doesn’t 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

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

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;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;

public class ExampleAppWidgetProvider extends AppWidgetProvider {
  DateFormat df = new SimpleDateFormat("hh:mm:ss");

  public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    final int N = appWidgetIds.length;

    Log.i("ExampleWidget",  "Updating widgets " + Arrays.asList(appWidgetIds));

    // Perform this loop procedure for each App Widget that belongs to this
    // provider
    for (int i = 0; i < N; i++) {
      int appWidgetId = appWidgetIds[i];

      // Create an Intent to launch ExampleActivity
      Intent intent = new Intent(context, WidgetExampleActivity.class);
      PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

      // Get the layout for the App Widget and attach an on-click listener
      // to the button
      RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget1);
      views.setOnClickPendingIntent(R.id.button, pendingIntent);

      // To update a label
      views.setTextViewText(R.id.widget1label, df.format(new Date()));

      // Tell the AppWidgetManager to perform an update on the current app
      // widget
      appWidgetManager.updateAppWidget(appWidgetId, views);
    }
  }
}

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 the setOnClickPendingIntent() 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.

Android Widget Figure 3

Figure 3

Android Widget Figure 4

Figure 4

Yay! Hang on, the clock isn’t updating! We set the update period to 1 second in our meta-data 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 doesn’t 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.

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Beginning Android Development.

Comments on this article are closed. Have a question about Android? Why not ask it on our forums?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • http://lifeapp.us matej

    When can we expect AlarmManager and widget example?

    • http://buildmobile.com Paul Bridgestock

      We should expect to hear from Bruce on the AlarmManager this coming week. Stay tuned, subscribe to the feeds, listen out on Twitter.

  • Jonah Brown

    What did you use for a code highlighter?

  • tim

    Hi

    Thank you very much for this great tutorial. It’s one of the most lucid out there. Please could you elaborate on how you could use PNG graphics rather than the drawn shapes? I’m finding it an impossible task.

    Best

  • http://www.androidwidget.info Android Widgets

    Hi Bruce,

    It’s a great article. Very complete. We liked so much that we are considering to add your article (link) to our guide about ‘how to create your own android widget’. We will read your next ones too, and give more feedback. Thanks.

  • http://www.xezco.com Ray Broadbridge

    Bruce, thanks very much. I have written on my print of your article ‘The best widget write up’ – and i’ve looked at a lot of them now. One behaviour I had with less well thought out widgets was that the button would stop responding. I see how you have mostly eliminated this. However I did see this problem once with your latest version which I have downloaded and can run on an N700. It also happens on the Eclipse emulator,but in that case the button never works.) I can reproduce the problem on the N700 by changing the default language in settings. Then the button stops responding until the N700 is restarted. Any thoughts on how to diagnose ?
    Cheers
    Ray

  • devedra

    MY question is that when i open the emulator the google and music widget is by default already on home screen…so i also want that same thing for my widget that when i open my emulator i can see my widget like google and music…
    plzzz help me and reply…
    i searched every where but i found nothing…

  • david barton

    Thanks Bruce. Cleanest article I have found to help to get started with widgets.

  • Khadar

    Hi Bruce,

    can you explain me how update the weather info. in my weather widget
    this is my semester project and it has deadline too.

    Thanks & regards

  • brijesh_patel

    good one . i like it. thanks a lot.

  • Lefinator

    Just wanted to say thanks! This was a great widget tutorial.

  • abhay mathur

    This is a good tutorial for App widgets. Thanks a lot….

  • http://ebusiness.netsmartz.net/android_app.asp GarryHillton

    Hi,

    I have the same question “please could you elaborate on how you could use PNG graphics rather than the drawn shapes?

  • Balu

    Can you please. tell me, how to show our widgets on locked screen?

  • http://www.topmaxtech.net top

    thank u very much

  • http://www.cheesegroup.com Steven

    Thanks for your tutorial. It’s so good.
    But if you also integrate AlarmManager to the project it would more useful.
    Nice day.

  • http://www.alohatech.net Raphael Cohen

    Thank you for such detailed work….means a lot to the independent developers.

  • http://android.com Janice

    Everything seems to compile for me… and I even see the onReceive() event fire.
    (So I know I’m doing SOMETHING right, here.)

    I see my Widget available from the widget-list.
    I even see my own widget configuration page.

    But when I try to add my widget to my home-page, I never actually see the widget.
    I see a toast msg that says “Application not installed on your phone”.

    Any ideas? How should I be “closing” my widget configuration page? With finish()? Or some other code?

    Thanks

  • http://android.com Janice

    > First, we want to add an action listener for our button so that when we click on it,
    > it opens up our main application.

    I didn’t think you want it to “open up” anything. Instead just: show the current time.

  • pankaj

    on click of widget i want to open one layout can i do ?if yes then how pls help me i want to open another screen in which i want to add edittext and button the thing in which user enter in edittext and submit it will display on widget…
    thanks adv.

  • Matt Hudson

    I really appreciate this one:
    “Google limits the update period to once every half an hour or greater.”

  • Abhilash

    Hi,
    It’s very nice tutorial and very helpful. I am having one more doubt, on click of button(on widget) just I want to change the background of the widget.. How can we do that. Can you explain please.