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