index.jd revision 1019a9c44e573d1eb44bf1733005afb46fb73f72
1page.title=App Widgets 2@jd:body 3 4<div id="qv-wrapper"> 5 <div id="qv"> 6 <h2>Quickview</h2> 7 <ul> 8 <li>App Widgets provide users access to some of your application features 9directly from the Home screen (without the need to launch an activity)</li> 10 <li>App Widgets are backed by a special kind of broadcast receiver that 11handles the App 12Widget lifecycle</li> 13 </ul> 14 15 <h2>In this document</h2> 16 <ol> 17 <li><a href="#Basics">The Basics</a></li> 18 <li><a href="#Manifest">Declaring an App Widget in the Manifest</a></li> 19 <li><a href="#MetaData">Adding the AppWidgetProviderInfo Metadata</a></li> 20 <li><a href="#CreatingLayout">Creating the App Widget Layout</a></li> 21 <li><a href="#AppWidgetProvider">Using the AppWidgetProvider Class</a> 22 <ol> 23 <li><a href="#ProviderBroadcasts">Receiving App Widget broadcast 24Intents</a></li> 25 </ol> 26 </li> 27 <li><a href="#Configuring">Creating an App Widget Configuration 28Activity</a> 29 <ol> 30 <li><a href="#UpdatingFromTheConfiguration">Updating the App Widget 31from 32 the configuration Activity</a></li> 33 </ol> 34 </li> 35 <li><a href="#preview">Setting a Preview Image</a></li> 36 <li><a href="#collections">Using App Widgets with Collections</a> 37 <ol> 38 <li><a href="#collection_sample">Sample application</a></li> 39 <li><a href="#implementing_collections">Implementing app widgets with 40collections 41</a></li> 42 <li><a href="#fresh">Keeping Collection Data Fresh</a></li> 43 </ol> 44 </li> 45 </ol> 46 47 <h2>Key classes</h2> 48 <ol> 49 <li>{@link android.appwidget.AppWidgetProvider}</li> 50 <li>{@link android.appwidget.AppWidgetProviderInfo}</li> 51 <li>{@link android.appwidget.AppWidgetManager}</li> 52 </ol> 53 54 <h2>See also</h2> 55 <ol> 56 <li><a 57href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 58Design 59 Guidelines</a></li> 60 <li><a 61href="http://android-developers.blogspot.com/2009/04/introducing-home-screen- 62widgets-and.html">Introducing 63 home screen widgets and the AppWidget framework »</a></li> 64 </ol> 65 </div> 66</div> 67 68 69<p>App Widgets are miniature application views that can be embedded in other 70applications 71(such as the Home screen) and receive periodic updates. These views are 72referred 73to as Widgets in the user interface, 74and you can publish one with an App Widget provider. An application component 75that is 76able to hold other App Widgets is called an App Widget host. The screenshot 77below shows 78the Music App Widget.</p> 79 80<img src="{@docRoot}images/appwidgets/appwidget.png" alt="" /> 81 82<p>This document describes how to publish an App Widget using an App Widget 83provider.</p> 84 85 86<h2 id="Basics">The Basics</h2> 87 88<p>To create an App Widget, you need the following:</p> 89 90<dl> 91 <dt>{@link android.appwidget.AppWidgetProviderInfo} object</dt> 92 <dd>Describes the metadata for an App Widget, such as the App Widget's layout, 93update frequency, 94 and the AppWidgetProvider class. This should be defined in XML.</dd> 95 <dt>{@link android.appwidget.AppWidgetProvider} class implementation</dt> 96 <dd>Defines the basic methods that allow you to programmatically interface 97with the App Widget, 98 based on broadcast events. Through it, you will receive broadcasts when the 99App Widget is updated, 100 enabled, disabled and deleted.</dd> 101 <dt>View layout</dt> 102 <dd>Defines the initial layout for the App Widget, defined in XML.</dd> 103</dl> 104 105<p>Additionally, you can implement an App Widget configuration Activity. This is 106an optional 107{@link android.app.Activity} that launches when the user adds your App Widget 108and allows him or her 109to modify App Widget settings at create-time.</p> 110 111<p>The following sections describe how to setup each of these components.</p> 112 113 114<h2 id="Manifest">Declaring an App Widget in the Manifest</h2> 115 116<p>First, declare the {@link android.appwidget.AppWidgetProvider} class in your 117application's 118<code>AndroidManifest.xml</code> file. For example:</p> 119 120<pre style="clear:right"> 121<receiver android:name="ExampleAppWidgetProvider" > 122 <intent-filter> 123 <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> 124 </intent-filter> 125 <meta-data android:name="android.appwidget.provider" 126 android:resource="@xml/example_appwidget_info" /> 127</receiver> 128</pre> 129 130<p>The <code><receiver></code> element requires the 131<code>android:name</code> 132attribute, which specifies the {@link android.appwidget.AppWidgetProvider} used 133by the App Widget.</p> 134 135<p>The <code><intent-filter></code> element must include an 136<code><action></code> 137element with the <code>android:name</code> attribute. This attribute specifies 138that the {@link android.appwidget.AppWidgetProvider} accepts the {@link 139android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE 140ACTION_APPWIDGET_UPDATE} broadcast. 141This is the only broadcast that you must explicitly declare. The {@link 142android.appwidget.AppWidgetManager} 143automatically sends all other App Widget broadcasts to the AppWidgetProvider as 144necessary.</p> 145 146<p>The <code><meta-data></code> element specifies the 147{@link android.appwidget.AppWidgetProviderInfo} resource and requires the 148following attributes:</p> 149<ul> 150 <li><code>android:name</code> - Specifies the metadata name. Use 151<code>android.appwidget.provider</code> 152 to identify the data as the {@link android.appwidget.AppWidgetProviderInfo} 153descriptor.</li> 154 <li><code>android:resource</code> - Specifies the {@link 155android.appwidget.AppWidgetProviderInfo} 156 resource location.</li> 157</ul> 158 159 160<h2 id="MetaData">Adding the AppWidgetProviderInfo Metadata</h2> 161 162<p>The {@link android.appwidget.AppWidgetProviderInfo} defines the essential 163qualities of an App Widget, such as its minimum layout dimensions, its initial 164layout resource, 165how often to update the App Widget, and (optionally) a configuration Activity to 166launch at create-time. 167Define the AppWidgetProviderInfo object in an XML resource using a single 168<code><appwidget-provider></code> element and save it in the project's 169<code>res/xml/</code> 170folder.</p> 171 172<p>For example:</p> 173 174<pre> 175<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 176 android:minWidth="294dp" 177 android:minHeight="72dp" 178 android:updatePeriodMillis="86400000" 179 android:previewImage="@drawable/preview" 180 android:initialLayout="@layout/example_appwidget" 181 android:configure="com.example.android.ExampleAppWidgetConfigure" 182 android:resizeMode="horizontal|vertical"> 183</appwidget-provider> 184</pre> 185 186<p>Here's a summary of the <code><appwidget-provider></code> attributes:</p> 187<ul> 188 <li>The values for the <code>minWidth</code> and <code>minHeight</code> 189 attributes specify the minimum amount of space the App Widget consumes 190 <em>by default</em>. The default Home screen positions App Widgets in its 191 window based on a grid of cells that have a defined height and width. If 192 the values for an App Widget's minimum width or height don't match the 193 dimensions of the cells, then the App Widget dimensions round 194 <em>up</em> to the nearest cell size. 195 <p>See the <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html#anatomy_determining_size"> 196 App Widget Design Guidelines</a> for more information on sizing your App 197 Widgets.</p> 198 199 <p class="note"><strong>Note:</strong> To make your app widget portable 200 across devices, your app widget's minimum size should never be larger 201 than 4 x 4 cells.</p> 202 </li> 203 204 <li>The <code>minResizeWidth</code> and <code>minResizeHeight</code> attributes 205 specify the App Widget's absolute minimum size. These values should specify 206 the size below which the App Widget would be illegible or otherwise unusable. 207 Using these attributes allows the user to resize the widget to a size that 208 may be smaller than the default widget size defined by the 209 <code>minWidth</code> and <code>minHeight</code> attributes. 210 Introduced in Android 3.1. 211 212 <p>See the <a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html#anatomy_determining_size"> 213 App Widget Design Guidelines</a> for more information on sizing your App 214 Widgets.</p> 215 </li> 216 217 <li>The <code>updatePeriodMillis</code> attribute defines how often the App 218Widget framework should request an update from the {@link 219android.appwidget.AppWidgetProvider} by calling the 220{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 221callback method. The actual update 222is not guaranteed to occur exactly on time with this value and we suggest 223updating as infrequently as possible—perhaps no more than once an hour to 224conserve the battery. You might also allow the user to adjust the frequency in a 225configuration—some people might want a stock ticker to update every 15 226minutes, or maybe only four times a day. 227 <p class="note"><strong>Note:</strong> If the device is asleep when it 228is time for an update 229 (as defined by <code>updatePeriodMillis</code>), then the device will 230wake up in order 231 to perform the update. If you don't update more than once per hour, this 232probably won't 233 cause significant problems for the battery life. If, however, you need 234to update more 235 frequently and/or you do not need to update while the device is asleep, 236then you can instead 237 perform updates based on an alarm that will not wake the device. To do 238so, set an alarm with 239 an Intent that your AppWidgetProvider receives, using the {@link 240android.app.AlarmManager}. 241 Set the alarm type to either {@link 242android.app.AlarmManager#ELAPSED_REALTIME} or 243 {@link android.app.AlarmManager#RTC}, which will only 244 deliver the alarm when the device is awake. Then set 245<code>updatePeriodMillis</code> to 246 zero (<code>"0"</code>).</p> 247 </li> 248 <li>The <code>initialLayout</code> attribute points to the layout resource 249that defines the 250 App Widget layout.</li> 251 <li>The <code>configure</code> attribute defines the {@link 252android.app.Activity} to launch when 253 the user adds the App Widget, in order for him or her to configure App 254Widget properties. This is optional 255 (read <a href="#Configuring">Creating an App Widget Configuration 256Activity</a> below).</li> 257 258 <li>The <code>previewImage</code> attribute specifies a preview of what the 259app widget will look like after it's configured, which the user sees when 260selecting the app widget. If not supplied, the user instead sees your 261application's launcher icon. This field corresponds to the 262<code>android:previewImage</code> attribute in the <code><receiver></code> 263element in the <code>AndroidManifest.xml</code> file. For more discussion of 264using <code>previewImage</code>, see <a href="#preview">Setting a Preview 265Image</a>. Introduced in Android 3.0.</li> 266 267 <li>The <code>autoAdvanceViewId</code> attribute specifies the view ID of the 268app widget subview that should be auto-advanced by the widget's host. Introduced in Android 3.0.</li> 269 270<li>The <code>resizeMode</code> attribute specifies the rules by which a widget 271can be resized. You use this attribute to make homescreen widgets 272resizeable—horizontally, vertically, or on both axes. Users touch-hold a 273widget to show its resize handles, then drag the horizontal and/or vertical 274handles to change the size on the layout grid. Values for the 275<code>resizeMode</code> attribute include "horizontal", "vertical", and "none". 276To declare a widget as resizeable horizontally and vertically, supply the value 277"horizontal|vertical". Introduced in Android 3.1.</li> </ul> 278 279<p>See the {@link android.appwidget.AppWidgetProviderInfo} class for more 280information on the 281attributes accepted by the <code><appwidget-provider></code> element.</p> 282 283 284<h2 id="CreatingLayout">Creating the App Widget Layout</h2> 285 286<p>You must define an initial layout for your App Widget in XML and save it in 287the project's 288<code>res/layout/</code> directory. You can design your App Widget using the 289View objects listed 290below, but before you begin designing your App Widget, please read and 291understand the 292<a href="{@docRoot}guide/practices/ui_guidelines/widget_design.html">App Widget 293Design 294Guidelines</a>.</p> 295 296<p>Creating the App Widget layout is simple if you're 297familiar with <a 298href="{@docRoot}guide/topics/ui/declaring-layout.html">Layouts</a>. 299However, you must be aware that App Widget layouts are based on {@link 300android.widget.RemoteViews}, 301which do not support every kind of layout or view widget.</p> 302 303<p>A RemoteViews object (and, consequently, an App Widget) can support the 304following layout classes:</p> 305 306<ul class="nolist"> 307 <li>{@link android.widget.FrameLayout}</li> 308 <li>{@link android.widget.LinearLayout}</li> 309 <li>{@link android.widget.RelativeLayout}</li> 310 <li>{@link android.widget.GridLayout}</li> 311</ul> 312 313<p>And the following widget classes:</p> 314<ul class="nolist"> 315 <li>{@link android.widget.AnalogClock}</li> 316 <li>{@link android.widget.Button}</li> 317 <li>{@link android.widget.Chronometer}</li> 318 <li>{@link android.widget.ImageButton}</li> 319 <li>{@link android.widget.ImageView}</li> 320 <li>{@link android.widget.ProgressBar}</li> 321 <li>{@link android.widget.TextView}</li> 322 <li>{@link android.widget.ViewFlipper}</li> 323 <li>{@link android.widget.ListView}</li> 324 <li>{@link android.widget.GridView}</li> 325 <li>{@link android.widget.StackView}</li> 326 <li>{@link android.widget.AdapterViewFlipper}</li> 327</ul> 328 329<p>Descendants of these classes are not supported.</p> 330 331<p>RemoteViews also supports {@link android.view.ViewStub}, which is an invisible, zero-sized View you can use 332to lazily inflate layout resources at runtime.</p> 333 334 335<h3 id="AddingMargins">Adding margins to App Widgets</h3> 336 337<p>Widgets should not generally extend to screen edges and should not visually be flush with other widgets, so you should add margins on all sides around your widget frame.</p> 338 339<p>As of Android 4.0, app widgets are automatically given padding between the widget frame and the app widget's bounding box to provide better alignment with other widgets and icons on the user's home screen. To take advantage of this strongly recommended behavior, set your application's <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html">targetSdkVersion</a> to 14 or greater.</p> 340 341<p>It's easy to write a single layout that has custom margins applied for earlier versions of the platform, and has no extra margins for Android 4.0 and greater:</p> 342 343<ol> 344 <li>Set your application's <code>targetSdkVersion</code> to 14 or greater.</li> 345 <li>Create a layout such as the one below, that references a <a href="{@docRoot}guide/topics/resources/more-resources.html#Dimension">dimension resource</a> for its margins: 346 347<pre> 348<FrameLayout 349 android:layout_width="match_parent" 350 android:layout_height="match_parent" 351 <strong>android:padding="@dimen/widget_margin"></strong> 352 353 <LinearLayout 354 android:layout_width="match_parent" 355 android:layout_height="match_parent" 356 android:orientation="horizontal" 357 android:background="@drawable/my_widget_background"> 358 … 359 </LinearLayout> 360 361</FrameLayout> 362</pre> 363 364 </li> 365 <li>Create two dimensions resources, one in <code>res/values/</code> to provide the pre-Android 4.0 custom margins, and one in <code>res/values-v14/</code> to provide no extra padding for Android 4.0 widgets: 366 367 <p><strong>res/values/dimens.xml</strong>:<br> 368 <pre><dimen name="widget_margin">8dp</dimen></pre></p> 369 370 <p><strong>res/values-v14/dimens.xml</strong>:<br> 371 <pre><dimen name="widget_margin">0dp</dimen></pre></p> 372 </li> 373</ol> 374 375<p>Another option is to simply build extra margins into your <a href="{@docRoot}guide/topics/graphics/2d-graphics.html#nine-patch">nine-patch</a> background assets by default, and provide different nine-patches with no margins for API level 14 or later.</p> 376 377 378<h2 id="AppWidgetProvider">Using the AppWidgetProvider Class</h2> 379 380<div class="sidebox-wrapper"> 381<div class="sidebox"> 382 <p>You must declare your AppWidgetProvider class implementation as a 383broadcast receiver 384 using the <code><receiver></code> element in the AndroidManifest (see 385 <a href="#Manifest">Declaring an App Widget in the Manifest</a> above).</p> 386 </div> 387</div> 388 389<p>The {@link android.appwidget.AppWidgetProvider} class extends 390BroadcastReceiver as a convenience 391class to handle the App Widget broadcasts. The AppWidgetProvider receives only 392the event broadcasts that 393are relevant to the App Widget, such as when the App Widget is updated, deleted, 394enabled, and disabled. 395When these broadcast events occur, the AppWidgetProvider receives the following 396method calls:</p> 397 398<dl> 399 <dt> 400 {@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context,android.appwidget.AppWidgetManager,int[]) onUpdate()} 401</dt> 402 <dd>This is called to update the App Widget at intervals defined by the 403<code>updatePeriodMillis</code> 404 attribute in the AppWidgetProviderInfo (see <a href="#MetaData">Adding the 405 AppWidgetProviderInfo Metadata</a> above). This method is also called 406 when the user adds the App Widget, so it should perform the essential setup, 407 such as define event handlers for Views and start a temporary 408 {@link android.app.Service}, if necessary. However, if you have declared a 409configuration 410 Activity, <strong>this method is not called</strong> when the user adds the 411App Widget, 412 but is called for the subsequent updates. It is the responsibility of the 413 configuration Activity to perform the first update when configuration is 414done. 415 (See <a href="#Configuring">Creating an App Widget Configuration 416Activity</a> below.)</dd> 417 418<dt> 419 {@link android.appwidget.AppWidgetProvider#onAppWidgetOptionsChanged onAppWidgetOptionsChanged()} 420</dt> 421<dd> 422This is called when the widget is first placed and any time the widget is resized. You can use this callback to show or hide content based on the widget's size ranges. You get the size ranges by calling {@link android.appwidget.AppWidgetManager#getAppWidgetOptions getAppWidgetOptions()}, which returns a {@link android.os.Bundle} that includes the following:<br /><br /> 423<ul> 424 <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MIN_WIDTH}—Contains 425the lower bound on the current width, in dp units, of a widget instance.</li> 426 <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MIN_HEIGHT}—Contains 427the lower bound on the current height, in dp units, of a widget instance.</li> 428 <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MAX_WIDTH}—Contains 429 the upper bound on the current width, in dp units, of a widget instance.</li> 430 <li>{@link android.appwidget.AppWidgetManager#OPTION_APPWIDGET_MAX_HEIGHT}—Contains 431the upper bound on the current width, in dp units, of a widget instance.</li> 432</ul> 433 434This callback was introduced in API Level 16 (Android 4.1). If you implement this callback, make sure that your app doesn't depend on it since it won't be called on older devices. 435</dd> 436 <dt>{@link android.appwidget.AppWidgetProvider#onDeleted(Context,int[])}</dt> 437 <dd>This is called every time an App Widget is deleted from the App Widget 438host.</dd> 439 <dt>{@link android.appwidget.AppWidgetProvider#onEnabled(Context)}</dt> 440 <dd>This is called when an instance the App Widget is created for the first 441time. For example, if the user 442 adds two instances of your App Widget, this is only called the first time. 443 If you need to open a new database or perform other setup that only needs to 444occur once 445 for all App Widget instances, then this is a good place to do it.</dd> 446 <dt>{@link android.appwidget.AppWidgetProvider#onDisabled(Context)}</dt> 447 <dd>This is called when the last instance of your App Widget is deleted from 448the App Widget host. 449 This is where you should clean up any work done in 450 {@link android.appwidget.AppWidgetProvider#onEnabled(Context)}, 451 such as delete a temporary database.</dd> 452 <dt>{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)}</dt> 453 <dd>This is called for every broadcast and before each of the above callback 454methods. 455 You normally don't need to implement this method because the default 456AppWidgetProvider 457 implementation filters all App Widget broadcasts and calls the above 458 methods as appropriate.</dd> 459</dl> 460 461<p class="warning"><strong>Note:</strong> In Android 1.5, there is a known issue 462in which the 463<code>onDeleted()</code> method will not be called when it should be. To work 464around this issue, 465you can implement {@link 466android.appwidget.AppWidgetProvider#onReceive(Context,Intent) 467onReceive()} as described in this 468<a 469href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2"> 470Group post</a> 471to receive the <code>onDeleted()</code> callback. 472</p> 473 474<p>The most important AppWidgetProvider callback is 475{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 476because it is called when 477each App Widget is added to a host (unless you use a configuration Activity). If 478your App Widget accepts any user interaction events, then you need to register 479the event handlers in this callback. If your App Widget doesn't create temporary 480files or databases, or perform other work that requires clean-up, then 481{@link android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 482may be the only callback 483method you need to define. For example, if you want an App Widget with a button 484that launches an Activity when clicked, you could use the following 485implementation of AppWidgetProvider:</p> 486 487<pre> 488public class ExampleAppWidgetProvider extends AppWidgetProvider { 489 490 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 491 final int N = appWidgetIds.length; 492 493 // Perform this loop procedure for each App Widget that belongs to this provider 494 for (int i=0; i<N; i++) { 495 int appWidgetId = appWidgetIds[i]; 496 497 // Create an Intent to launch ExampleActivity 498 Intent intent = new Intent(context, ExampleActivity.class); 499 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); 500 501 // Get the layout for the App Widget and attach an on-click listener 502 // to the button 503 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout); 504 views.setOnClickPendingIntent(R.id.button, pendingIntent); 505 506 // Tell the AppWidgetManager to perform an update on the current app widget 507 appWidgetManager.updateAppWidget(appWidgetId, views); 508 } 509 } 510} 511</pre> 512 513<p>This AppWidgetProvider defines only the 514{@link 515android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, android.appwidget.AppWidgetManager, int[]) onUpdate()} 516method for the purpose of 517defining a {@link android.app.PendingIntent} that launches an {@link 518android.app.Activity} and attaching it to the App Widget's button with {@link 519android.widget.RemoteViews#setOnClickPendingIntent(int,PendingIntent)}. Notice 520that it includes a loop that iterates through each entry in 521<code>appWidgetIds</code>, which is an array of IDs that identify each App 522Widget created by this provider. In this way, if the user creates more than one 523instance of the App Widget, then they are all updated simultaneously. However, 524only one <code>updatePeriodMillis</code> schedule will be managed for all 525instances of the App Widget. For example, if the update schedule is defined to 526be every two hours, and a second instance of the App Widget is added one hour 527after the first one, then they will both be updated on the period defined by the 528first one and the second update period will be ignored (they'll both be updated 529every two hours, not every hour).</p> 530 531<p class="note"><strong>Note:</strong> Because {@link 532android.appwidget.AppWidgetProvider} is an extension of {@link 533android.content.BroadcastReceiver}, your process is not guaranteed to keep 534running after the callback methods return (see {@link 535android.content.BroadcastReceiver} for information about the broadcast 536lifecycle). If your App Widget setup process can take several seconds (perhaps 537while performing web requests) and you require that your process continues, 538consider starting a {@link android.app.Service} in the 539{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 540method. From within the Service, you can perform your own updates 541to the App Widget without worrying about the AppWidgetProvider closing down due 542to an <a href="{@docRoot}guide/practices/responsiveness.html">Application 543Not Responding</a> (ANR) error. See the <a 544href="http://code.google.com/p/wiktionary-android/source/browse/trunk/Wiktionary/src/com/example/android/wiktionary/WordWidget.java">Wiktionary sample's AppWidgetProvider</a> for an example of an App Widget running a {@link 545android.app.Service}.</p> 546 547<p>Also see the <a 548href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetProvider.html">ExampleAppWidgetProvider.java</a> 549sample class.</p> 550 551 552<h3 id="ProviderBroadcasts">Receiving App Widget broadcast Intents</h3> 553 554<p>{@link android.appwidget.AppWidgetProvider} is just a convenience class. If 555you would like 556to receive the App Widget broadcasts directly, you can implement your own 557{@link android.content.BroadcastReceiver} or override the 558{@link android.appwidget.AppWidgetProvider#onReceive(Context,Intent)} callback. 559The Intents you need to care about are as follows:</p> 560<ul> 561 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_UPDATE}</li> 562 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DELETED}</li> 563 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_ENABLED}</li> 564 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_DISABLED}</li> 565 <li>{@link android.appwidget.AppWidgetManager#ACTION_APPWIDGET_OPTIONS_CHANGED}</li> 566</ul> 567 568 569 570<h2 id="Configuring">Creating an App Widget Configuration Activity</h2> 571 572<p>If you would like the user to configure settings when he or she adds a new 573App Widget, 574you can create an App Widget configuration Activity. This {@link 575android.app.Activity} 576will be automatically launched by the App Widget host and allows the user to 577configure 578available settings for the App Widget at create-time, such as the App Widget 579color, size, 580update period or other functionality settings.</p> 581 582<p>The configuration Activity should be declared as a normal Activity in the 583Android manifest file. 584However, it will be launched by the App Widget host with the {@link 585android.appwidget.AppWidgetManager#ACTION_APPWIDGET_CONFIGURE 586ACTION_APPWIDGET_CONFIGURE} action, 587so the Activity needs to accept this Intent. For example:</p> 588 589<pre> 590<activity android:name=".ExampleAppWidgetConfigure"> 591 <intent-filter> 592 <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/> 593 </intent-filter> 594</activity> 595</pre> 596 597<p>Also, the Activity must be declared in the AppWidgetProviderInfo XML file, 598with the 599<code>android:configure</code> attribute (see <a href="#MetaData">Adding 600the AppWidgetProviderInfo Metadata</a> above). For example, the configuration 601Activity 602can be declared like this:</p> 603 604<pre> 605<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 606 ... 607 android:configure="com.example.android.ExampleAppWidgetConfigure" 608 ... > 609</appwidget-provider> 610</pre> 611 612<p>Notice that the Activity is declared with a fully-qualified namespace, 613because 614it will be referenced from outside your package scope.</p> 615 616<p>That's all you need to get started with a configuration Activity. Now all you 617need is the actual 618Activity. There are, however, two important things to remember when you 619implement the Activity:</p> 620<ul> 621 <li>The App Widget host calls the configuration Activity and the configuration 622Activity should always 623 return a result. The result should include the App Widget ID 624 passed by the Intent that launched the Activity (saved in the Intent extras 625as 626 {@link android.appwidget.AppWidgetManager#EXTRA_APPWIDGET_ID}).</li> 627 <li>The 628 {@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 629 method <strong>will not be called</strong> when the App Widget 630is created 631 (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a 632configuration Activity 633 is launched). It is the responsibility of the configuration Activity to 634request an update from the 635 AppWidgetManager when the App Widget is first created. However, 636{@link android.appwidget.AppWidgetProvider#onUpdate(Context,AppWidgetManager,int[]) onUpdate()} 637 will be called for subsequent updates—it is only skipped 638the first time.</li> 639</ul> 640 641<p>See the code snippets in the following section for an example of how to 642return a result 643from the configuration and update the App Widget.</p> 644 645 646<h3 id="UpdatingFromTheConfiguration">Updating the App Widget from the 647configuration Activity</h3> 648 649<p>When an App Widget uses a configuration Activity, it is the responsibility of 650the Activity 651to update the App Widget when configuration is complete. 652You can do so by requesting an update directly from the 653{@link android.appwidget.AppWidgetManager}.</p> 654 655<p>Here's a summary of the procedure to properly update the App Widget and close 656the configuration Activity:</p> 657 658<ol> 659 <li>First, get the App Widget ID from the Intent that launched the Activity: 660<pre> 661Intent intent = getIntent(); 662Bundle extras = intent.getExtras(); 663if (extras != null) { 664 mAppWidgetId = extras.getInt( 665 AppWidgetManager.EXTRA_APPWIDGET_ID, 666 AppWidgetManager.INVALID_APPWIDGET_ID); 667} 668</pre> 669 </li> 670 <li>Perform your App Widget configuration.</li> 671 <li>When the configuration is complete, get an instance of the 672AppWidgetManager by calling 673 {@link android.appwidget.AppWidgetManager#getInstance(Context)}: 674<pre> 675AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); 676</pre> 677 </li> 678 <li>Update the App Widget with a {@link android.widget.RemoteViews} layout by 679calling 680 {@link android.appwidget.AppWidgetManager#updateAppWidget(int,RemoteViews)}: 681<pre> 682RemoteViews views = new RemoteViews(context.getPackageName(), 683R.layout.example_appwidget); 684appWidgetManager.updateAppWidget(mAppWidgetId, views); 685</pre> 686 </li> 687 <li>Finally, create the return Intent, set it with the Activity result, and 688finish the Activity:</li> 689<pre> 690Intent resultValue = new Intent(); 691resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); 692setResult(RESULT_OK, resultValue); 693finish(); 694</pre> 695 </li> 696</ol> 697 698<p class="note"><strong>Tip:</strong> When your configuration Activity first 699opens, set 700the Activity result to RESULT_CANCELED. This way, if the user backs-out of the 701Activity before 702reaching the end, the App Widget host is notified that the configuration was 703cancelled and the 704App Widget will not be added.</p> 705 706<p>See the <a 707href="{@docRoot}resources/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.html">ExampleAppWidgetConfigure.java</a> 708sample class in ApiDemos for an example.</p> 709 710<h2 id="preview">Setting a Preview Image</h2> 711 712<p>Android 3.0 introduces the {@link 713 714 715android.appwidget.AppWidgetProviderInfo#previewImage} field, which specifies a 716preview of what the app widget looks like. This preview is shown to the user from the 717widget picker. If this field is not supplied, the app widget's icon is used for 718the preview.</p> 719 720<p>This is how you specify this setting in XML:</p> 721 722<pre><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" 723 ... 724 android:previewImage="@drawable/preview"> 725</appwidget-provider></pre> 726 727<p>To help create a preview image for your app widget (to specify in the {@link 728android.appwidget.AppWidgetProviderInfo#previewImage} field), the Android 729emulator includes an application called "Widget Preview." To create a 730preview image, launch this application, select the app widget for your 731application and set it up how you'd like your preview image to appear, then save 732it and place it in your application's drawable resources.</p> 733 734<h2 id="collections">Using App Widgets with Collections</h2> 735 736<p>Android 3.0 introduces App Widgets with collections. These kinds of App 737Widgets use the {@link android.widget.RemoteViewsService} to display collections 738that are backed by remote data, such as from a <a 739href="{@docRoot}guide/topics/providers/content-providers.html">content 740provider</a>. The data provided by the {@link android.widget.RemoteViewsService} 741is presented in the App Widget using one of the following view types, which 742we’ll refer to as “collection views:”</p> 743 744<dl> 745 <dt>{@link android.widget.ListView}</dt> 746 <dd>A view that shows items in a 747vertically scrolling 748list. For an example, see the Gmail app widget. </dd> 749<dt>{@link android.widget.GridView}</dt> 750<dd>A view that shows items in 751two-dimensional scrolling grid. For an example, see the Bookmarks app 752widget.</dd> 753<dt>{@link android.widget.StackView}</dt> 754<dd>A 755stacked card view (kind of like a rolodex), where the user can flick the front 756card up/down to see the previous/next card, respectively. Examples include 757the YouTube and Books app widgets. </dd> 758<dt>{@link android.widget.AdapterViewFlipper}</dt> 759<dd>An adapter-backed simple 760{@link 761android.widget.ViewAnimator} that animates between two or more views. Only one 762child is shown at a time. </dd> 763</dl> 764 765<p>As stated above, these collection views display collections backed by remote 766data. This means that they use an {@link android.widget.Adapter} to bind their 767user interface to their data. An {@link android.widget.Adapter} binds individual 768items from a set of data into individual {@link android.view.View} objects. 769Because these collection views are backed by adapters, the Android framework 770must include extra architecture to support their use in app widgets. In the 771context of an app widget, the {@link android.widget.Adapter} is replaced by a 772{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, 773which is simply a thin wrapper around the {@link android.widget.Adapter} 774interface. 775 When 776requested for a specific item in the collection, the {@link 777android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} creates 778and returns the item for the collection as a {@link android.widget.RemoteViews} 779object. 780In order to include a collection view in your app widget, you 781must implement {@link android.widget.RemoteViewsService} and {@link 782android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}.</p> 783 784<p> {@link android.widget.RemoteViewsService} is a service that allows a remote 785adapter to request {@link 786android.widget.RemoteViews} objects. {@link 787android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} is an 788interface for an adapter between a collection view (such as {@link 789android.widget.ListView}, {@link android.widget.GridView}, and so on) and the 790underlying data for that view. From the <a 791href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 792sample</a>, here is an example of the boilerplate code you use to implement 793this service and interface: 794</p> 795 796<pre> 797public class StackWidgetService extends RemoteViewsService { 798 @Override 799 public RemoteViewsFactory onGetViewFactory(Intent intent) { 800 return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 801 } 802} 803 804class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { 805 806//... include adapter-like methods here. See the StackView Widget sample. 807 808} 809</pre> 810 811<h3 id="collection_sample">Sample application</h3> 812 813<p>The code excerpts in this section are drawn from the <a 814href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 815sample</a>:</p> 816 817<p> 818<img src="{@docRoot}images/appwidgets/StackWidget.png" alt="" /> 819</p> 820 821<p>This sample consists of a stack of 10 views, which display the values 822<code>"0!"</code> through <code>"9!"</code> The sample 823app widget has these primary behaviors:</p> 824 825<ul> 826 827 <li>The user can vertically fling the top view in the 828app widget to display the next or previous view. This is a built-in StackView 829behavior.</li> 830 831 <li>Without any user interaction, the app widget automatically advances 832through 833its views in sequence, like a slide show. This is due to the setting 834<code>android:autoAdvanceViewId="@id/stack_view"</code> in the 835<code>res/xml/stackwidgetinfo.xml</code> file. This setting applies to the view 836ID, 837which in this case is the view ID of the stack view.</li> 838 839 <li>If the user touches the top view, the app widget displays the {@link 840android.widget.Toast} message "Touched view <em>n</em>," where 841<em>n</em> is the index (position) of the touched view. For more discussion of 842how this is implemented, see 843<a href="#behavior">Adding behavior to individual items</a>.</li> 844 845</ul> 846<h3 id="implementing_collections">Implementing app widgets with collections</h3> 847 848<p>To implement an App Widget with collections, you follow the same basic steps 849you would use to implement any app widget. The following sections describe the 850additional steps you need to perform to implement an App Widget with 851collections.</p> 852 853<h4>Manifest for app widgets with collections</h4> 854 855<p> In addition to the requirements listed in <a href="#Manifest">Declaring an 856App Widget in the Manifest</a>, to make it possible for App Widgets with 857collections to bind to your {@link android.widget.RemoteViewsService}, you must 858declare the service in your manifest file with the permission {@link 859android.Manifest.permission#BIND_REMOTEVIEWS}. This prevents other applications 860from freely accessing your app widget's data. For example, when creating an App 861Widget that uses {@link android.widget.RemoteViewsService} to populate a 862collection view, the manifest entry may look like this:</p> 863 864<pre><service android:name="MyWidgetService" 865... 866android:permission="android.permission.BIND_REMOTEVIEWS" /></pre> 867 868<p>The line <code>android:name="MyWidgetService"</code> 869refers to your subclass of {@link android.widget.RemoteViewsService}. </p> 870 871<h4>Layout for app widgets with collections</h4> 872 873<p>The main requirement for your app widget layout XML file is that it 874include one of the collection views: {@link android.widget.ListView}, 875{@link android.widget.GridView}, {@link android.widget.StackView}, or 876{@link android.widget.AdapterViewFlipper}. Here is the 877<code>widget_layout.xml</code> for 878the <a href="{@docRoot}resources/samples/StackWidget/index.html">StackView 879Widget sample</a>:</p> 880 881<pre><?xml version="1.0" encoding="utf-8"?> 882 883<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 884 android:layout_width="match_parent" 885 android:layout_height="match_parent"> 886 <StackView xmlns:android="http://schemas.android.com/apk/res/android" 887 android:id="@+id/stack_view" 888 android:layout_width="match_parent" 889 android:layout_height="match_parent" 890 android:gravity="center" 891 android:loopViews="true" /> 892 <TextView xmlns:android="http://schemas.android.com/apk/res/android" 893 android:id="@+id/empty_view" 894 android:layout_width="match_parent" 895 android:layout_height="match_parent" 896 android:gravity="center" 897 android:background="@drawable/widget_item_background" 898 android:textColor="#ffffff" 899 android:textStyle="bold" 900 android:text="@string/empty_view_text" 901 android:textSize="20sp" /> 902</FrameLayout></pre> 903 904<p> Note that empty views must be siblings of the collection view for which the 905empty view represents empty state. </p> 906 907<p>In addition to the layout file for your entire app widget, you must create 908another layout file that defines the layout for each item in the collection (for 909example, a layout for each book in a collection of books). For example, the <a 910href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 911sample</a> only has one layout file, <code>widget_item.xml</code>, since all 912items use the same layout. But the <a 913href="{@docRoot}resources/samples/WeatherListWidget/index.html"> 914WeatherListWidget sample</a> has two layout files: 915<code>dark_widget_item.xml</code> and <code>light_widget_item.xml</code>.</p> 916 917 918 919<h4 id="AppWidgetProvider-collections">AppWidgetProvider class for app widgets with collections</h4> 920 921<p>As with a regular app widget, the bulk of your code in your {@link 922android.appwidget.AppWidgetProvider} subclass typically goes in {@link 923android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 924android.appwidget.AppWidgetManager, int[]) onUpdate()}. The major difference in 925your implementation for {@link 926android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 927android.appwidget.AppWidgetManager, int[]) onUpdate()} when creating an app 928widget with collections is that you must call {@link 929android.widget.RemoteViews#setRemoteAdapter setRemoteAdapter()}. This tells the 930collection view where to get its data. The {@link 931android.widget.RemoteViewsService} can then return your implementation of {@link 932android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, and 933the widget can serve up the appropriate data. When you call this method, you 934must pass an intent that points to your implementation of {@link 935android.widget.RemoteViewsService} and the App Widget ID that specifies the app 936widget to update.</p> 937 938 939<p>For example, here's how the StackView Widget sample implements the {@link 940android.appwidget.AppWidgetProvider#onUpdate(android.content.Context, 941android.appwidget.AppWidgetManager, int[]) onUpdate()} callback method to set 942the {@link 943android.widget.RemoteViewsService} as the remote adapter for the app widget 944collection:</p> 945 946<pre>public void onUpdate(Context context, AppWidgetManager appWidgetManager, 947int[] appWidgetIds) { 948 // update each of the app widgets with the remote adapter 949 for (int i = 0; i < appWidgetIds.length; ++i) { 950 951 // Set up the intent that starts the StackViewService, which will 952 // provide the views for this collection. 953 Intent intent = new Intent(context, StackWidgetService.class); 954 // Add the app widget ID to the intent extras. 955 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); 956 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); 957 // Instantiate the RemoteViews object for the App Widget layout. 958 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 959 // Set up the RemoteViews object to use a RemoteViews adapter. 960 // This adapter connects 961 // to a RemoteViewsService through the specified intent. 962 // This is how you populate the data. 963 rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent); 964 965 // The empty view is displayed when the collection has no items. 966 // It should be in the same layout used to instantiate the RemoteViews 967 // object above. 968 rv.setEmptyView(R.id.stack_view, R.id.empty_view); 969 970 // 971 // Do additional processing specific to this app widget... 972 // 973 974 appWidgetManager.updateAppWidget(appWidgetIds[i], rv); 975 } 976 super.onUpdate(context, appWidgetManager, appWidgetIds); 977}</pre> 978 979<h4>RemoteViewsService class</h4> 980 981<div class="sidebox-wrapper"> 982<div class="sidebox"> 983<h3>Persisting data</h3> 984 <p>You can’t rely on a single instance of your service, or any data it 985contains, to persist. You should therefore not store any data in your {@link 986android.widget.RemoteViewsService} (unless it is static). If you want your 987app widget’s data to persist, the best approach is to use a {@link 988android.content.ContentProvider} whose data persists beyond the process 989lifecycle.</p> </div> 990</div> 991 992<p>As described above, your {@link android.widget.RemoteViewsService} subclass 993provides the {@link android.widget.RemoteViewsService.RemoteViewsFactory 994RemoteViewsFactory} used to populate the remote collection view.</p> 995 996<p>Specifically, you need to 997perform these steps:</p> 998 999<ol> 1000 <li>Subclass {@link android.widget.RemoteViewsService}. {@link 1001android.widget.RemoteViewsService} is the service through which 1002a remote adapter can request {@link android.widget.RemoteViews}. </li> 1003 1004 <li>In your {@link android.widget.RemoteViewsService} subclass, include a 1005class that implements the {@link 1006android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1007interface. {@link android.widget.RemoteViewsService.RemoteViewsFactory 1008RemoteViewsFactory} is an interface for an adapter between a remote collection 1009view (such as {@link android.widget.ListView}, {@link android.widget.GridView}, 1010and so on) and the underlying data for that view. Your implementation is 1011responsible for making a {@link android.widget.RemoteViews} object for each 1012item in the data set. This interface is a thin wrapper around {@link 1013android.widget.Adapter}.</li> 1014</ol> 1015 1016<p>The primary contents of the {@link android.widget.RemoteViewsService} 1017implementation is its {@link 1018android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, 1019described below.</p> 1020 1021<h4>RemoteViewsFactory interface</h4> 1022 1023<p>Your custom class that implements the {@link 1024android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1025interface provides the app widget with the data for the items in its collection. 1026To 1027do this, it combines your app widget item XML layout file with a source of data. 1028This source of data could be anything from a database to a simple array. In the 1029<a href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1030sample</a>, the data source is an array of <code>WidgetItems</code>. The {@link 1031android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1032functions as an adapter to glue the data to the remote collection view.</p> 1033 1034<p>The two most important methods you need to implement for your 1035 1036{@link android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1037subclass are 1038{@link android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() 1039onCreate()} and 1040{@link android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) 1041getViewAt()} 1042.</p> 1043 1044<p>The system calls {@link 1045android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} when 1046creating your factory for the first time. This is where you set up any 1047connections and/or cursors to your data source. For example, the <a 1048href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1049sample</a> uses {@link 1050android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} to 1051initialize an array of <code>WidgetItem</code> objects. When your app widget is 1052active, the system accesses these objects using their index position in the 1053array and the text they contain is displayed </p> 1054 1055<p>Here is an excerpt from the the <a 1056href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget</a> 1057sample's 1058{@link android.widget.RemoteViewsService.RemoteViewsFactory 1059RemoteViewsFactory} implementation that shows portions of the {@link 1060android.widget.RemoteViewsService.RemoteViewsFactory#onCreate() onCreate()} 1061method:</p> 1062 1063<pre>class StackRemoteViewsFactory implements 1064RemoteViewsService.RemoteViewsFactory { 1065 private static final int mCount = 10; 1066 private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>(); 1067 private Context mContext; 1068 private int mAppWidgetId; 1069 1070 public StackRemoteViewsFactory(Context context, Intent intent) { 1071 mContext = context; 1072 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 1073 AppWidgetManager.INVALID_APPWIDGET_ID); 1074 } 1075 1076 public void onCreate() { 1077 // In onCreate() you setup any connections / cursors to your data source. Heavy lifting, 1078 // for example downloading or creating content etc, should be deferred to onDataSetChanged() 1079 // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR. 1080 for (int i = 0; i < mCount; i++) { 1081 mWidgetItems.add(new WidgetItem(i + "!")); 1082 } 1083 ... 1084 } 1085...</pre> 1086 1087<p>The {@link android.widget.RemoteViewsService.RemoteViewsFactory 1088RemoteViewsFactory} method {@link 1089android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()} 1090returns a {@link android.widget.RemoteViews} object corresponding to the data at 1091the specified <code>position</code> in the data set. Here is an excerpt from 1092the <a 1093href="http://developer.android.com/resources/samples/StackWidget/index.html"> 1094StackView Widget</a> sample's {@link 1095android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} 1096implementation:</p> 1097 1098<pre>public RemoteViews getViewAt(int position) { 1099 1100 // Construct a remote views item based on the app widget item XML file, 1101 // and set the text based on the position. 1102 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); 1103 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text); 1104 1105 ... 1106 // Return the remote views object. 1107 return rv; 1108}</pre> 1109 1110<h4 id="behavior">Adding behavior to individual items</h4> 1111 1112<p>The above sections show you how to bind your data to your app widget 1113collection. But what if you want to add dynamic behavior to the individual items 1114in your collection view?</p> 1115 1116<p> As described in <a href="#AppWidgetProvider">Using the AppWidgetProvider 1117Class</a>, you normally use {@link 1118android.widget.RemoteViews#setOnClickPendingIntent(int, 1119android.app.PendingIntent) setOnClickPendingIntent()} to set an object's click 1120behavior—such as to cause a button to launch an {@link 1121android.app.Activity}. But this approach is not allowed for child views in an 1122individual collection item (to clarify, you could use {@link 1123android.widget.RemoteViews#setOnClickPendingIntent(int, 1124android.app.PendingIntent) setOnClickPendingIntent()} to set up a global button 1125in the Gmail app widget that launches the app, for example, but not on the 1126individual list items). Instead, to add click behavior to individual items in a 1127collection, you use {@link 1128android.widget.RemoteViews#setOnClickFillInIntent(int, android.content.Intent) 1129setOnClickFillInIntent()}. This entails setting up up a pending intent template 1130for your collection view, and then setting a fill-in intent on each item in the 1131collection via your {@link android.widget.RemoteViewsService.RemoteViewsFactory 1132RemoteViewsFactory}.</p> 1133<p>This section uses the <a 1134href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1135sample</a> to describe how to add behavior to individual items. In the <a 1136href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1137sample</a>, if the user touches the top view, the app widget displays the {@link 1138android.widget.Toast} message "Touched view <em>n</em>," where 1139<em>n</em> is the index (position) of the touched view. This is how it 1140works:</p> 1141 1142<ul> 1143 <li>The <code>StackWidgetProvider</code> (an {@link 1144android.appwidget.AppWidgetProvider} subclass) creates a pending intent that has 1145a custom action called <code>TOAST_ACTION</code>.</li> 1146 <li>When the user touches a view, the intent is fired and it broadcasts 1147<code>TOAST_ACTION</code>.</li> 1148 1149 <li>This broadcast is intercepted by the <code>StackWidgetProvider</code>'s 1150{@link android.appwidget.AppWidgetProvider#onReceive(android.content.Context, 1151android.content.Intent) onReceive()} method, and the app widget displays the 1152{@link 1153android.widget.Toast} message for the touched view. The data for the collection 1154items is provided by the {@link 1155android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}, via 1156the {@link android.widget.RemoteViewsService}.</li> 1157</ul> 1158 1159<p class="note"><strong>Note:</strong> The <a 1160href="{@docRoot}resources/samples/StackWidget/index.html">StackView Widget 1161sample</a> uses a broadcast, but typically an app widget would simply launch an 1162activity in a scenario like this one.</p> 1163 1164<h5>Setting up the pending intent template</h5> 1165 1166<p>The <code>StackWidgetProvider</code> ({@link 1167android.appwidget.AppWidgetProvider} subclass) sets up a pending intent. 1168Individuals items of a collection cannot set up their own pending intents. 1169Instead, the collection as a whole sets up a pending intent template, and the 1170individual items set a fill-in intent to create unique behavior on an 1171item-by-item 1172basis.</p> 1173 1174<p>This class also receives the broadcast that is sent when the user touches a 1175view. It processes this event in its {@link 1176android.appwidget.AppWidgetProvider#onReceive(android.content.Context, 1177android.content.Intent) onReceive()} method. If the intent's action is 1178<code>TOAST_ACTION</code>, the app widget displays a {@link 1179android.widget.Toast} 1180message for the current view.</p> 1181 1182<pre>public class StackWidgetProvider extends AppWidgetProvider { 1183 public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION"; 1184 public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM"; 1185 1186 ... 1187 1188 // Called when the BroadcastReceiver receives an Intent broadcast. 1189 // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget 1190 // displays a Toast message for the current item. 1191 @Override 1192 public void onReceive(Context context, Intent intent) { 1193 AppWidgetManager mgr = AppWidgetManager.getInstance(context); 1194 if (intent.getAction().equals(TOAST_ACTION)) { 1195 int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 1196 AppWidgetManager.INVALID_APPWIDGET_ID); 1197 int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0); 1198 Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show(); 1199 } 1200 super.onReceive(context, intent); 1201 } 1202 1203 @Override 1204 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { 1205 // update each of the app widgets with the remote adapter 1206 for (int i = 0; i < appWidgetIds.length; ++i) { 1207 1208 // Sets up the intent that points to the StackViewService that will 1209 // provide the views for this collection. 1210 Intent intent = new Intent(context, StackWidgetService.class); 1211 intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); 1212 // When intents are compared, the extras are ignored, so we need to embed the extras 1213 // into the data so that the extras will not be ignored. 1214 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); 1215 RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout); 1216 rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent); 1217 1218 // The empty view is displayed when the collection has no items. It should be a sibling 1219 // of the collection view. 1220 rv.setEmptyView(R.id.stack_view, R.id.empty_view); 1221 1222 // This section makes it possible for items to have individualized behavior. 1223 // It does this by setting up a pending intent template. Individuals items of a collection 1224 // cannot set up their own pending intents. Instead, the collection as a whole sets 1225 // up a pending intent template, and the individual items set a fillInIntent 1226 // to create unique behavior on an item-by-item basis. 1227 Intent toastIntent = new Intent(context, StackWidgetProvider.class); 1228 // Set the action for the intent. 1229 // When the user touches a particular view, it will have the effect of 1230 // broadcasting TOAST_ACTION. 1231 toastIntent.setAction(StackWidgetProvider.TOAST_ACTION); 1232 toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]); 1233 intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME))); 1234 PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent, 1235 PendingIntent.FLAG_UPDATE_CURRENT); 1236 rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent); 1237 1238 appWidgetManager.updateAppWidget(appWidgetIds[i], rv); 1239 } 1240 super.onUpdate(context, appWidgetManager, appWidgetIds); 1241 } 1242}</pre> 1243 1244<h5><strong>Setting the fill-in Intent</strong></h5> 1245 1246<p>Your {@link android.widget.RemoteViewsService.RemoteViewsFactory 1247RemoteViewsFactory} must set a fill-in intent on each item in the collection. 1248This makes it possible to distinguish the individual on-click action of a given 1249item. The fill-in intent is then combined with the {@link 1250android.app.PendingIntent} template in order to determine the final intent that 1251will be executed when the item is clicked. </p> 1252 1253<pre> 1254public class StackWidgetService extends RemoteViewsService { 1255 @Override 1256 public RemoteViewsFactory onGetViewFactory(Intent intent) { 1257 return new StackRemoteViewsFactory(this.getApplicationContext(), intent); 1258 } 1259} 1260 1261class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory { 1262 private static final int mCount = 10; 1263 private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>(); 1264 private Context mContext; 1265 private int mAppWidgetId; 1266 1267 public StackRemoteViewsFactory(Context context, Intent intent) { 1268 mContext = context; 1269 mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, 1270 AppWidgetManager.INVALID_APPWIDGET_ID); 1271 } 1272 1273 // Initialize the data set. 1274 public void onCreate() { 1275 // In onCreate() you set up any connections / cursors to your data source. Heavy lifting, 1276 // for example downloading or creating content etc, should be deferred to onDataSetChanged() 1277 // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR. 1278 for (int i = 0; i < mCount; i++) { 1279 mWidgetItems.add(new WidgetItem(i + "!")); 1280 } 1281 ... 1282 } 1283 ... 1284 1285 // Given the position (index) of a WidgetItem in the array, use the item's text value in 1286 // combination with the app widget item XML file to construct a RemoteViews object. 1287 public RemoteViews getViewAt(int position) { 1288 // position will always range from 0 to getCount() - 1. 1289 1290 // Construct a RemoteViews item based on the app widget item XML file, and set the 1291 // text based on the position. 1292 RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item); 1293 rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text); 1294 1295 // Next, set a fill-intent, which will be used to fill in the pending intent template 1296 // that is set on the collection view in StackWidgetProvider. 1297 Bundle extras = new Bundle(); 1298 extras.putInt(StackWidgetProvider.EXTRA_ITEM, position); 1299 Intent fillInIntent = new Intent(); 1300 fillInIntent.putExtras(extras); 1301 // Make it possible to distinguish the individual on-click 1302 // action of a given item 1303 rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent); 1304 1305 ... 1306 1307 // Return the RemoteViews object. 1308 return rv; 1309 } 1310 ... 1311 }</pre> 1312 1313<h3 id="fresh">Keeping Collection Data Fresh</h3> 1314 1315<p>The following figure illustrates the flow that occurs in an App Widget that 1316uses 1317collections when updates occur. It shows how the App Widget code interacts with 1318the {@link android.widget.RemoteViewsService.RemoteViewsFactory 1319RemoteViewsFactory}, and how you can trigger updates:</p> 1320 1321<img src="{@docRoot}images/appwidgets/appwidget_collections.png" alt="" /> 1322 1323<p>One feature of App Widgets that use collections is the ability to provide 1324users with up-to-date content. For example, consider the Android 3.0 Gmail 1325app widget, which provides users with a snapshot of their inbox. To make this 1326possible, you need to be able to trigger your {@link 1327android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory} and 1328collection view to fetch and display new data. You achieve this with the {@link 1329android.appwidget.AppWidgetManager} call {@link 1330android.appwidget.AppWidgetManager#notifyAppWidgetViewDataChanged(int, int) 1331notifyAppWidgetViewDataChanged()}. This call results in a callback to your 1332<code>RemoteViewsFactory</code>’s {@link 1333android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged() 1334onDataSetChanged()} method, which gives you the opportunity to fetch any new 1335data. Note that you can perform 1336processing-intensive operations synchronously within the {@link 1337android.widget.RemoteViewsService.RemoteViewsFactory#onDataSetChanged() 1338onDataSetChanged()} callback. You are guaranteed that this call will be 1339completed before the metadata or view data is fetched from the {@link 1340android.widget.RemoteViewsService.RemoteViewsFactory RemoteViewsFactory}. In 1341addition, you can perform processing-intensive operations within the {@link 1342android.widget.RemoteViewsService.RemoteViewsFactory#getViewAt(int) getViewAt()} 1343method. If this call takes a long time, the loading view (specified by the 1344<code>RemoteViewsFactory</code>’s {@link 1345android.widget.RemoteViewsService.RemoteViewsFactory#getLoadingView()} method) 1346will be displayed in the corresponding position of the collection view until it 1347returns.</p> 1348 1349 1350