You are on page 1of 9

Home

Tutorials

Training

Books

Connect

Android Homescreen Widgets- Tutorial


Lars Vogel
Version 2.2
Copyright 2009, 2010, 2011, 2012 Lars Vogel

by Lars Vogel
Tutorial
178

18.05.2012
Revision History Revision 0.1 Created Revision 0.2 - 2.2 bug fixes and enhancements 13.12.2010 - 18.05.2012 Lars Vogel 01.09.2010 Lars Vogel

Android Training Eclipse Training

Developing Android Widgets This article describes how to create widgets in Android. It is based on Eclipse 3.7, Java 1.6 and Android 4.0.4 (Ice Cream Sandwich).

Table of Contents
1. Android Widgets 1.1. Homescreen Widgets 1.2. Steps to create a Widget 1.3. Register Widget 1.4. Available views and layouts 1.5. Widget size 1.6. Widget updates 1.7. AppWidgetProvider 2. Prerequisites 3. Example with fixed update interval 4. Update via a service and onClickListener 5. Thank you 6. Questions and Discussion 7. Links and Literature 7.1. Source Code 7.2. Android Widget Resources 7.3. Android Resources 7.4. vogella Resources

1. Android Widgets
1.1. Homescreen Widgets
Widgets are little applications which can be placed on the home screen of your Android device. An Widget gets its data on a periodic timetable. There are two methods to update a widget, one is based on an XML configuration file and the other is based on the Android AlarmManager service.

A Widget runs as part of the homescreen process. This requires that Widgets preserve the permissions of their application.
Widgets use RemoteViews to create there user interface. A RemoteView can be executed by another process with the same permissions as the original application. This way the Widget runs with the

permissions of its defining application. The user interface for an Widget is defined by an BroadcastReceiver. This BroadcastReceiver inflates its layout into an object of type RemoteViews. This RemoteViews object is delivered to Android, which hands it over the HomeScreen application.

1.2. Steps to create a Widget


To create a Widget you: Define a layout file for your Widget.
converted by Web2PDFConvert.com

Maintain an XML file (AppWidgetProviderInfo) which describes the properties of the widget, e.g. size or the fixed update frequency. Create a BroadcastReceiver which will be used to build the user interface of the Widgets. This receiver extends the AppWidgetProvider class which provides additional lifecycle hooks for Widgets. Maintain the App Widget configuration in the AndroidManifest.xml file. You can also specify a configuration Activity which is called once a new instance instance of the widget is added to the Android homescreen.

1.3. Register Widget


To register a widget you create a BroadcastReceiver which an intent filter for the action android.appwidget.action.APPWIDGET_UPDATE.
<receiver android:icon="@drawable/icon" android:label="Example Widget" android:name="MyWidgetProvider" > <intent-filter > <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver>

The BroadcastReceiver can get an label and and icon assigned. These are used in the list of available Widgets. You also specify the meta-data for the widget via the
android:name="android.appwidget.provider" attribute. The configuration file referred to by this meta-data contains the configuration settings for the widget. If contains for example the update interface, the size and the initial layout before the first update() call on the widget.
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_layout" android:minHeight="72dp" android:minWidth="146dp" android:updatePeriodMillis="180000" > </appwidget-provider>

1.4. Available views and layouts


A widget is restricted in the elements it can use. For layouts you can use FrameLayout, LinearLayout and RelativeLayout. As views you can use AnalogClock, Button, Chromometer, ImageButton, ImageView, ProgressBar and TextView. As of Android 3.0 more views are available: GridView, ListView, StackView, ViewFlipper and AdapterViewFlipper. The only interaction with is possible on the Views of a Widget is via on OnClickListener. This OnClickListener can be registered on a widget and is triggered by the user.

1.5. Widget size


A Widget will take a certain amount of cells on the homescreen. A cell is usually used to display the icon of one application. As a calculation rule you should define the size of the widget with the formula: ((Number of columns / rows)* 74) - 2. These are device independent pixels and the -2 is used to avoid rounding issues. As of Android 3.1 a Widgets can be flexible in size, e.g. the user can make is larger or smaller. To enable this for Widgets you can use the android:resizeMode="horizontal|vertical" atttribute in the XML configuration file for the widget.

1.6. Widget updates


In the widget configuration file you can specify a fixed update interval. The system will wake up after this time interval and call your broadcast receiver to udpate the widget. The smallest update interval is 180000 milliseconds (30 minutes).

converted by Web2PDFConvert.com

The AlarmManager allows you to be more resource efficient and to have a higher frequency of updates. Here you see an example configuration file for a widget.
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_layout" android:minHeight="72dp" android:minWidth="146dp" android:updatePeriodMillis="180000" > </appwidget-provider>

1.7. AppWidgetProvider
Your BroadcastReceiver extends AppWidgetProvider. The AppWidgetProvider class implements the onReceive() method, extracts the required information and calls the following widget lifecycle methods. As you can added several instances of a widget to the homescreen you have lifecycle methods which are called only for the first instance added / removed to the homescreen and others which are called for every instance of your widget. Table 1. Lifecycle method
Method onEnabled() onDisabled() onUpdate() Description Called the first time an instance of your widget is added to the homescreen Called once the last instance of your widget is removed from the homescreen. Called for every update of the widget. Contains the ids of appWidgetIds for which an update is needed. Note that this may be all of the AppWidget instances for this provider, or just a subset of them, as stated in the methods JavaDoc. For example if more than one widget is added to the homescreen, only the last one changes (until reinstall). Widget instance is removed from the homescreen

onDeleted()

All long running operations in these methods should be performed in a service, as the execution time for a broadcast receiver is limited. Using asynchronous processing in the onReceive() method does not help as the system can kill the broadcast process after his onReceive() method.

2. Prerequisites
The following description assume that you have already experience in building standard Android application. Please see Android Tutorial . It also uses partly Android services. You find an introduction into Android Services in Android Service Tutorial .

3. Example with fixed update interval


The following will create a simple example for a widget. We will create a widget which displays a random number. This random number will updated automatically every 30 minutes. We will also register a OnClickListener so that the widgets update if the user click on it. The resulting widget will look like the following.

converted by Web2PDFConvert.com

Create a new Android project de.vogella.android.widget.example with no Activity in the package de.vogella.android.widget.example. Create a new file myshape.xml under the path "/res/drawable-mdpi". This file will define the background we use in your widget.
<?xml version="1.0" encoding="UTF-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <stroke android:width="2dp" android:color="#FFFFFFFF" /> <gradient android:angle="225" android:endColor="#DD2ECCFA" android:startColor="#DD000000" /> <corners android:bottomLeftRadius="7dp" android:bottomRightRadius="7dp" android:topLeftRadius="7dp" android:topRightRadius="7dp" /> </shape>

Define the following widget_layout.xml file under the res/layout folder.


<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/layout" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="8dip" android:background="@drawable/myshape" > <TextView android:id="@+id/update" style="@android:style/TextAppearance.Medium" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" android:gravity="center_horizontal|center_vertical" android:layout_margin="4dip" android:text="Static Text" > </TextView> </LinearLayout>

Create the AppWidgetProvider metadata file "widget_info.xml", via File New Android Android XML File

converted by Web2PDFConvert.com

<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/widget_layout" android:minHeight="72dp" android:minWidth="300dp" android:updatePeriodMillis="300000" > </appwidget-provider>

Create the BroadcastReeceiver which will be called for updates. We also register an OnClickListener on the view of the PendingIntent.
package de.vogella.android.widget.example; import java.util.Random; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.RemoteViews; public class MyWidgetProvider extends AppWidgetProvider { private static final String ACTION_CLICK = "ACTION_CLICK";

@Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { // Get all ids ComponentName thisWidget = new ComponentName(context, MyWidgetProvider.class); int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

converted by Web2PDFConvert.com

for (int widgetId : allWidgetIds) { // Create some random data int number = (new Random().nextInt(100)); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout); Log.w("WidgetExample", String.valueOf(number)); // Set the text remoteViews.setTextViewText(R.id.update, String.valueOf(number));

// Register an onClickListener Intent intent = new Intent(context, MyWidgetProvider.class);


intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent); appWidgetManager.updateAppWidget(widgetId, remoteViews); } } }

Open AndroidManifest.xml and maintain the following.


<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="de.vogella.android.widget.example" android:versionCode="1" android:versionName="1.0" > <application android:icon="@drawable/icon" android:label="@string/app_name" > <receiver android:name="MyWidgetProvider" > <intent-filter > <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget_info" /> </receiver> </application> <uses-sdk android:minSdkVersion="8" /> </manifest>

This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast and specifies the metadata for the widget. Run your app. Once your app has been deployed, long press on your desktop and install your new widget.

converted by Web2PDFConvert.com

4. Update via a service and onClickListener


A BroadcastReceiver must finish his onReceive() method within 5 secs. For potentially long running actions, as for example network access, you should do this processing in a service and perform the update the widgets from the service. The following will demonstrate the usage of a service to update the widget. Create the following UpdateWidgetService class in your project.
package de.vogella.android.widget.example; import java.util.Random; import android.app.PendingIntent; import android.app.Service; import android.appwidget.AppWidgetManager; import android.content.ComponentName; import android.content.Intent; import android.os.IBinder; import android.util.Log; import android.widget.RemoteViews; public class UpdateWidgetService extends Service { private static final String LOG = "de.vogella.android.widget.example";

@Override public void onStart(Intent intent, int startId) { Log.i(LOG, "Called"); // Create some random data
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this .getApplicationContext()); int[] allWidgetIds = intent .getIntArrayExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS); ComponentName thisWidget = new ComponentName(getApplicationContext(), MyWidgetProvider.class); int[] allWidgetIds2 = appWidgetManager.getAppWidgetIds(thisWidget); Log.w(LOG, "From Intent" + String.valueOf(allWidgetIds.length)); Log.w(LOG, "Direct" + String.valueOf(allWidgetIds2.length)); for (int widgetId : allWidgetIds) { // Create some random data int number = (new Random().nextInt(100)); RemoteViews remoteViews = new RemoteViews(this .getApplicationContext().getPackageName(), R.layout.widget_layout); Log.w("WidgetExample", String.valueOf(number)); // Set the text remoteViews.setTextViewText(R.id.update, "Random: " + String.valueOf(number));

// Register an onClickListener Intent clickIntent = new Intent(this.getApplicationContext(), MyWidgetProvider.class);


clickIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE); clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS,

converted by Web2PDFConvert.com

allWidgetIds); PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.update, pendingIntent); appWidgetManager.updateAppWidget(widgetId, remoteViews); } stopSelf(); super.onStart(intent, startId); }

@Override public IBinder onBind(Intent intent) { return null; } }

Add this class as a Service to your AndroidManifest.xml.


<service android:name=".UpdateWidgetService"></service>

Change MyWidgetProvider to the following. It will now only construct the service and start it.
package de.vogella.android.widget.example; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.util.Log; public class MyWidgetProvider extends AppWidgetProvider { private static final String LOG = "de.vogella.android.widget.example";

@Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {


Log.w(LOG, "onUpdate method called"); // Get all ids ComponentName thisWidget = new ComponentName(context, MyWidgetProvider.class); int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

// Build the intent to call the service Intent intent = new Intent(context.getApplicationContext(), UpdateWidgetService.class); intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, allWidgetIds); // Update the widgets via the service context.startService(intent); } }

Once called this service will update all widgets. You can click on one of the widgets to update all widgets.

5. Thank you
Please help me to support this article:

6. Questions and Discussion


Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.

7. Links and Literature


7.1. Source Code
Source Code of Examples

7.2. Android Widget Resources


Example Widget from Android API demos

converted by Web2PDFConvert.com

Wiktionary Example Widget http://code.google.com/p/wiktionaryandroid/source/browse/trunk/Wiktionary/src/com/example/android/wiktionary/

7.3. Android Resources


Introduction to Android Development Background processing in Android Android Service and BroadcastReceiver Tutorial Android Location API and Google Maps

7.4. vogella Resources


Eclipse RCP Training (German) Eclipse RCP Training with Lars Vogel Android Tutorial Introduction to Android Programming GWT Tutorial Program in Java and compile to JavaScript and HTML Eclipse RCP Tutorial Create native applications in Java JUnit Tutorial Test your application Git Tutorial Put everything you have under distributed version control system

converted by Web2PDFConvert.com

You might also like