App Widgets

App Widgets are miniature application views that can be embedded in other applications (such as the Home screen) and receive periodic updates. These views are referred to as Widgets in the user interface, and you can publish one with an App Widget provider. An application component that is able to hold other App Widgets is called an App Widget host. The screenshot below shows the Music App Widget.

This document describes how to publish an App Widget using an App Widget provider. For a discussion of creating your ownAppWidgetHost to host app widgets, see App Widget Host.

Widget Design

For information about how to design your app widget, read theWidgets design guide.

The Basics


To create an App Widget, you need the following:

AppWidgetProviderInfo object
Describes the metadata for an App Widget, such as the App Widget's layout, update frequency, and the AppWidgetProvider class. This should be defined in XML.
AppWidgetProvider class implementation
Defines the basic methods that allow you to programmatically interface with the App Widget, based on broadcast events. Through it, you will receive broadcasts when the App Widget is updated, enabled, disabled and deleted.
View layout
Defines the initial layout for the App Widget, defined in XML.

Additionally, you can implement an App Widget configuration Activity. This is an optional Activity that launches when the user adds your App Widget and allows him or her to modify App Widget settings at create-time.

The following sections describe how to set up each of these components.

Declaring an App Widget in the Manifest


First, declare the AppWidgetProvider class in your application's AndroidManifest.xml file. For example:

<receiver android:name="ExampleAppWidgetProvider" >
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />
</receiver>

The <receiver> element requires the android:name attribute, which specifies the AppWidgetProvider used by the App Widget.

The <intent-filter> element must include an <action> element with the android:name attribute. This attribute specifies that the AppWidgetProvider accepts the ACTION_APPWIDGET_UPDATE broadcast. This is the only broadcast that you must explicitly declare. The AppWidgetManager automatically sends all other App Widget broadcasts to the AppWidgetProvider as necessary.

The <meta-data> element specifies the AppWidgetProviderInfo resource and requires the following attributes:

  • android:name - Specifies the metadata name. Use android.appwidget.provider to identify the data as theAppWidgetProviderInfo descriptor.
  • android:resource - Specifies the AppWidgetProviderInfo resource location.

Adding the AppWidgetProviderInfo Metadata


The AppWidgetProviderInfo defines the essential qualities of an App Widget, such as its minimum layout dimensions, its initial layout resource, how often to update the App Widget, and (optionally) a configuration Activity to launch at create-time. Define the AppWidgetProviderInfo object in an XML resource using a single<appwidget-provider> element and save it in the project's res/xml/ folder.

For example:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:updatePeriodMillis="86400000"
    android:previewImage="@drawable/preview"
    android:initialLayout="@layout/example_appwidget"
    android:configure="com.example.android.ExampleAppWidgetConfigure" 
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen">
</appwidget-provider>

Here's a summary of the <appwidget-provider> attributes:

  • The values for the minWidth and minHeight attributes specify the minimum amount of space the App Widget consumes by default. The default Home screen positions App Widgets in its window based on a grid of cells that have a defined height and width. If the values for an App Widget's minimum width or height don't match the dimensions of the cells, then the App Widget dimensions round up to the nearest cell size.

    See the App Widget Design Guidelines for more information on sizing your App Widgets.

    Note: To make your app widget portable across devices, your app widget's minimum size should never be larger than 4 x 4 cells.

  • The minResizeWidth and minResizeHeight attributes specify the App Widget's absolute minimum size. These values should specify the size below which the App Widget would be illegible or otherwise unusable. Using these attributes allows the user to resize the widget to a size that may be smaller than the default widget size defined by the minWidth and minHeight attributes. Introduced in Android 3.1.

    See the App Widget Design Guidelines for more information on sizing your App Widgets.

  • The updatePeriodMillis attribute defines how often the App Widget framework should request an update from the AppWidgetProvider by calling the onUpdate() callback method. The actual update is not guaranteed to occur exactly on time with this value and we suggest updating as infrequently as possible—perhaps no more than once an hour to conserve the battery. You might also allow the user to adjust the frequency in a configuration—some people might want a stock ticker to update every 15 minutes, or maybe only four times a day.

    Note: If the device is asleep when it is time for an update (as defined by updatePeriodMillis), then the device will wake up in order to perform the update. If you don't update more than once per hour, this probably won't cause significant problems for the battery life. If, however, you need to update more frequently and/or you do not need to update while the device is asleep, then you can instead perform updates based on an alarm that will not wake the device. To do so, set an alarm with an Intent that your AppWidgetProvider receives, using the AlarmManager. Set the alarm type to either ELAPSED_REALTIME orRTC, which will only deliver the alarm when the device is awake. Then set updatePeriodMillis to zero ("0").

  • The initialLayout attribute points to the layout resource that defines the App Widget layout.
  • The configure attribute defines the Activity to launch when the user adds the App Widget, in order for him or her to configure App Widget properties. This is optional (read Creating an App Widget Configuration Activity below).
  • The previewImage attribute specifies a preview of what the app widget will look like after it's configured, which the user sees when selecting the app widget. If not supplied, the user instead sees your application's launcher icon. This field corresponds to the android:previewImage attribute in the <receiver> element in the AndroidManifest.xml file. For more discussion of using previewImage, see Setting a Preview Image. Introduced in Android 3.0.
  • The autoAdvanceViewId attribute specifies the view ID of the app widget subview that should be auto-advanced by the widget's host. Introduced in Android 3.0.
  • The resizeMode attribute specifies the rules by which a widget can be resized. You use this attribute to make homescreen widgets resizeable—horizontally, vertically, or on both axes. Users touch-hold a widget to show its resize handles, then drag the horizontal and/or vertical handles to change the size on the layout grid. Values for the resizeMode attribute include "horizontal", "vertical", and "none". To declare a widget as resizeable horizontally and vertically, supply the value "horizontal|vertical". Introduced in Android 3.1.
  • The minResizeHeight attribute specifies the minimum height (in dps) to which the widget can be resized. This field has no effect if it is greater than minHeight or if vertical resizing isn't enabled (see resizeMode). Introduced in Android 4.0.
  • The minResizeWidth attribute specifies the minimum width (in dps) to which the widget can be resized. This field has no effect if it is greater than minWidth or if horizontal resizing isn't enabled (see resizeMode). Introduced in Android 4.0.
  • The widgetCategory attribute declares whether your App Widget can be displayed on the home screen (home_screen), the lock screen (keyguard), or both. Only Android versions lower than 5.0 support lock-screen widgets. For Android 5.0 and higher, only home_screen is valid.

See the AppWidgetProviderInfo class for more information on the attributes accepted by the <appwidget-provider> element.

Creating the App Widget Layout


You must define an initial layout for your App Widget in XML and save it in the project's res/layout/ directory. You can design your App Widget using the View objects listed below, but before you begin designing your App Widget, please read and understand the App Widget Design Guidelines.

Creating the App Widget layout is simple if you're familiar with Layouts. However, you must be aware that App Widget layouts are based on RemoteViews, which do not support every kind of layout or view widget.

A RemoteViews object (and, consequently, an App Widget) can support the following layout classes:

And the following widget classes:

Descendants of these classes are not supported.

RemoteViews also supports ViewStub, which is an invisible, zero-sized View you can use to lazily inflate layout resources at runtime.

Adding margins to App Widgets

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.

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 targetSdkVersion to 14 or greater.

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:

  1. Set your application's targetSdkVersion to 14 or greater.
  2. Create a layout such as the one below, that references a dimension resource for its margins:
    <FrameLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:padding="@dimen/widget_margin">
    
      <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="horizontal"
        android:background="@drawable/my_widget_background">
        …
      </LinearLayout>
    
    </FrameLayout>
  3. Create two dimensions resources, one in res/values/ to provide the pre-Android 4.0 custom margins, and one in res/values-v14/ to provide no extra padding for Android 4.0 widgets:

    res/values/dimens.xml:

    <dimen name="widget_margin">8dp</dimen>

    res/values-v14/dimens.xml:

    <dimen name="widget_margin">0dp</dimen>

Another option is to simply build extra margins into your nine-patch background assets by default, and provide different nine-patches with no margins for API level 14 or later.

Using the AppWidgetProvider Class


The AppWidgetProvider class extends BroadcastReceiver as a convenience class to handle the App Widget broadcasts. The AppWidgetProvider receives only the event broadcasts that are relevant to the App Widget, such as when the App Widget is updated, deleted, enabled, and disabled. When these broadcast events occur, the AppWidgetProvider receives the following method calls:

onUpdate()
This is called to update the App Widget at intervals defined by the  updatePeriodMillis attribute in the AppWidgetProviderInfo (see  Adding the AppWidgetProviderInfo Metadata above). This method is also called when the user adds the App Widget, so it should perform the essential setup, such as define event handlers for Views and start a temporary  Service, if necessary. However, if you have declared a configuration Activity,  this method is not called when the user adds the App Widget, but is called for the subsequent updates. It is the responsibility of the configuration Activity to perform the first update when configuration is done. (See  Creating an App Widget Configuration Activity below.)
onAppWidgetOptionsChanged()
This 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 getAppWidgetOptions(), which returns a  Bundle that includes the following:

This 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.
onDeleted(Context, int[])
This is called every time an App Widget is deleted from the App Widget host.
onEnabled(Context)
This is called when an instance the App Widget is created for the first time. For example, if the user adds two instances of your App Widget, this is only called the first time. If you need to open a new database or perform other setup that only needs to occur once for all App Widget instances, then this is a good place to do it.
onDisabled(Context)
This is called when the last instance of your App Widget is deleted from the App Widget host. This is where you should clean up any work done in  onEnabled(Context), such as delete a temporary database.
onReceive(Context, Intent)
This is called for every broadcast and before each of the above callback methods. You normally don't need to implement this method because the default AppWidgetProvider implementation filters all App Widget broadcasts and calls the above methods as appropriate.

The most important AppWidgetProvider callback is onUpdate() because it is called when each App Widget is added to a host (unless you use a configuration Activity). If your App Widget accepts any user interaction events, then you need to register the event handlers in this callback. If your App Widget doesn't create temporary files or databases, or perform other work that requires clean-up, then onUpdate() may be the only callback method you need to define. For example, if you want an App Widget with a button that launches an Activity when clicked, you could use the following implementation of AppWidgetProvider:

public class ExampleAppWidgetProvider extends AppWidgetProvider {

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

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

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

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

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

This AppWidgetProvider defines only the onUpdate() method for the purpose of defining a PendingIntentthat launches an Activity and attaching it to the App Widget's button with setOnClickPendingIntent(int, PendingIntent). Notice that it includes a loop that iterates through each entry in appWidgetIds, which is an array of IDs that identify each App Widget created by this provider. In this way, if the user creates more than one instance of the App Widget, then they are all updated simultaneously. However, only one updatePeriodMillisschedule will be managed for all instances of the App Widget. For example, if the update schedule is defined to be every two hours, and a second instance of the App Widget is added one hour after the first one, then they will both be updated on the period defined by the first one and the second update period will be ignored (they'll both be updated every two hours, not every hour).

Note: Because AppWidgetProvider is an extension of BroadcastReceiver, your process is not guaranteed to keep running after the callback methods return (see BroadcastReceiver for information about the broadcast lifecycle). If your App Widget setup process can take several seconds (perhaps while performing web requests) and you require that your process continues, consider starting a Service in the onUpdate()method. From within the Service, you can perform your own updates to the App Widget without worrying about the AppWidgetProvider closing down due to an Application Not Responding (ANR) error. See theWiktionary sample's AppWidgetProvider for an example of an App Widget running a Service.

Also see the ExampleAppWidgetProvider.java sample class.

Receiving App Widget broadcast Intents

AppWidgetProvider is just a convenience class. If you would like to receive the App Widget broadcasts directly, you can implement your own BroadcastReceiver or override the onReceive(Context, Intent) callback. The Intents you need to care about are as follows:

Creating an App Widget Configuration Activity


If you would like the user to configure settings when he or she adds a new App Widget, you can create an App Widget configuration Activity. This Activity will be automatically launched by the App Widget host and allows the user to configure available settings for the App Widget at create-time, such as the App Widget color, size, update period or other functionality settings.

The configuration Activity should be declared as a normal Activity in the Android manifest file. However, it will be launched by the App Widget host with the ACTION_APPWIDGET_CONFIGURE action, so the Activity needs to accept this Intent. For example:

<activity android:name=".ExampleAppWidgetConfigure">
    <intent-filter>
        <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>
    </intent-filter>
</activity>

Also, the Activity must be declared in the AppWidgetProviderInfo XML file, with the android:configure attribute (see Adding the AppWidgetProviderInfo Metadata above). For example, the configuration Activity can be declared like this:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    ...
    android:configure="com.example.android.ExampleAppWidgetConfigure" 
    ... >
</appwidget-provider>

Notice that the Activity is declared with a fully-qualified namespace, because it will be referenced from outside your package scope.

That's all you need to get started with a configuration Activity. Now all you need is the actual Activity. There are, however, two important things to remember when you implement the Activity:

  • The App Widget host calls the configuration Activity and the configuration Activity should always return a result. The result should include the App Widget ID passed by the Intent that launched the Activity (saved in the Intent extras as EXTRA_APPWIDGET_ID).
  • The onUpdate() method will not be called when the App Widget is created (the system will not send the ACTION_APPWIDGET_UPDATE broadcast when a configuration Activity is launched). It is the responsibility of the configuration Activity to request an update from the AppWidgetManager when the App Widget is first created. However, onUpdate() will be called for subsequent updates—it is only skipped the first time.

See the code snippets in the following section for an example of how to return a result from the configuration and update the App Widget.

Updating the App Widget from the configuration Activity

When an App Widget uses a configuration Activity, it is the responsibility of the Activity to update the App Widget when configuration is complete. You can do so by requesting an update directly from the AppWidgetManager.

Here's a summary of the procedure to properly update the App Widget and close the configuration Activity:

  1. First, get the App Widget ID from the Intent that launched the Activity:
    Intent intent = getIntent();
    Bundle extras = intent.getExtras();
    if (extras != null) {
        mAppWidgetId = extras.getInt(
                AppWidgetManager.EXTRA_APPWIDGET_ID, 
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }
  2. Perform your App Widget configuration.
  3. When the configuration is complete, get an instance of the AppWidgetManager by callinggetInstance(Context):
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
  4. Update the App Widget with a RemoteViews layout by calling updateAppWidget(int, RemoteViews):
    RemoteViews views = new RemoteViews(context.getPackageName(),
    R.layout.example_appwidget);
    appWidgetManager.updateAppWidget(mAppWidgetId, views);
  5. Finally, create the return Intent, set it with the Activity result, and finish the Activity:
    Intent resultValue = new Intent();
    resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
    setResult(RESULT_OK, resultValue);
    finish();

Tip: When your configuration Activity first opens, set the Activity result to RESULT_CANCELED. This way, if the user backs-out of the Activity before reaching the end, the App Widget host is notified that the configuration was cancelled and the App Widget will not be added.

See the ExampleAppWidgetConfigure.java sample class in ApiDemos for an example.

Setting a Preview Image


Android 3.0 introduces the previewImage field, which specifies a preview of what the app widget looks like. This preview is shown to the user from the widget picker. If this field is not supplied, the app widget's icon is used for the preview.

This is how you specify this setting in XML:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
  ...
  android:previewImage="@drawable/preview">
</appwidget-provider>

To help create a preview image for your app widget (to specify in the previewImage field), the Android emulator includes an application called "Widget Preview." To create a preview image, launch this application, select the app widget for your application and set it up how you'd like your preview image to appear, then save it and place it in your application's drawable resources.

Using App Widgets with Collections


Android 3.0 introduces app widgets with collections. These kinds of App Widgets use the RemoteViewsServiceto display collections that are backed by remote data, such as from a content provider. The data provided by theRemoteViewsService is presented in the app widget using one of the following view types, which we’ll refer to as “collection views:”

ListView
A view that shows items in a vertically scrolling list. For an example, see the Gmail app widget.
GridView
A view that shows items in two-dimensional scrolling grid. For an example, see the Bookmarks app widget.
StackView
A stacked card view (kind of like a rolodex), where the user can flick the front card up/down to see the previous/next card, respectively. Examples include the YouTube and Books app widgets. 
AdapterViewFlipper
An adapter-backed simple  ViewAnimator that animates between two or more views. Only one child is shown at a time.

As stated above, these collection views display collections backed by remote data. This means that they use anAdapter to bind their user interface to their data. An Adapter binds individual items from a set of data into individual View objects. Because these collection views are backed by adapters, the Android framework must include extra architecture to support their use in app widgets. In the context of an app widget, the Adapter is replaced by a RemoteViewsFactory, which is simply a thin wrapper around the Adapter interface. When requested for a specific item in the collection, the RemoteViewsFactory creates and returns the item for the collection as a RemoteViews object. In order to include a collection view in your app widget, you must implement RemoteViewsService and RemoteViewsFactory.

RemoteViewsService is a service that allows a remote adapter to request RemoteViews objects.RemoteViewsFactory is an interface for an adapter between a collection view (such as ListViewGridView, and so on) and the underlying data for that view. From the StackView Widget sample, here is an example of the boilerplate code you use to implement this service and interface:

public class StackWidgetService extends RemoteViewsService {
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
    }
}

class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {

//... include adapter-like methods here. See the StackView Widget sample.

}

Sample application

The code excerpts in this section are drawn from the StackView Widget sample:

This sample consists of a stack of 10 views, which display the values "0!" through "9!" The sample app widget has these primary behaviors:

  • The user can vertically fling the top view in the app widget to display the next or previous view. This is a built-in StackView behavior.
  • Without any user interaction, the app widget automatically advances through its views in sequence, like a slide show. This is due to the setting android:autoAdvanceViewId="@id/stack_view" in theres/xml/stackwidgetinfo.xml file. This setting applies to the view ID, which in this case is the view ID of the stack view.
  • If the user touches the top view, the app widget displays the Toast message "Touched view n," where n is the index (position) of the touched view. For more discussion of how this is implemented, see Adding behavior to individual items.

Implementing app widgets with collections

To implement an app widget with collections, you follow the same basic steps you would use to implement any app widget. The following sections describe the additional steps you need to perform to implement an app widget with collections.

Manifest for app widgets with collections

In addition to the requirements listed in Declaring an app widget in the Manifest, to make it possible for app widgets with collections to bind to your RemoteViewsService, you must declare the service in your manifest file with the permission BIND_REMOTEVIEWS. This prevents other applications from freely accessing your app widget's data. For example, when creating an App Widget that uses RemoteViewsService to populate a collection view, the manifest entry may look like this:

<service android:name="MyWidgetService"
...
android:permission="android.permission.BIND_REMOTEVIEWS" />

The line android:name="MyWidgetService" refers to your subclass of RemoteViewsService.

Layout for app widgets with collections

The main requirement for your app widget layout XML file is that it include one of the collection views:ListViewGridViewStackView, or AdapterViewFlipper. Here is the widget_layout.xml for theStackView Widget sample:

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

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
    <StackView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/stack_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:loopViews="true" />
    <TextView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/empty_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:background="@drawable/widget_item_background"
        android:textColor="#ffffff"
        android:textStyle="bold"
        android:text="@string/empty_view_text"
        android:textSize="20sp" />
</FrameLayout>

Note that empty views must be siblings of the collection view for which the empty view represents empty state.

In addition to the layout file for your entire app widget, you must create another layout file that defines the layout for each item in the collection (for example, a layout for each book in a collection of books). For example, theStackView Widget sample only has one layout file, widget_item.xml, since all items use the same layout. But the WeatherListWidget sample has two layout files: dark_widget_item.xml and light_widget_item.xml.

AppWidgetProvider class for app widgets with collections

As with a regular app widget, the bulk of your code in your AppWidgetProvider subclass typically goes inonUpdate(). The major difference in your implementation for onUpdate() when creating an app widget with collections is that you must call setRemoteAdapter(). This tells the collection view where to get its data. TheRemoteViewsService can then return your implementation of RemoteViewsFactory, and the widget can serve up the appropriate data. When you call this method, you must pass an intent that points to your implementation of RemoteViewsService and the app widget ID that specifies the app widget to update.

For example, here's how the StackView Widget sample implements the onUpdate() callback method to set theRemoteViewsService as the remote adapter for the app widget collection:

public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
    // update each of the app widgets with the remote adapter
    for (int i = 0; i < appWidgetIds.length; ++i) {
        
        // Set up the intent that starts the StackViewService, which will
        // provide the views for this collection.
        Intent intent = new Intent(context, StackWidgetService.class);
        // Add the app widget ID to the intent extras.
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
        intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
        // Instantiate the RemoteViews object for the app widget layout.
        RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
        // Set up the RemoteViews object to use a RemoteViews adapter. 
        // This adapter connects
        // to a RemoteViewsService  through the specified intent.
        // This is how you populate the data.
        rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
        
        // The empty view is displayed when the collection has no items. 
        // It should be in the same layout used to instantiate the RemoteViews
        // object above.
        rv.setEmptyView(R.id.stack_view, R.id.empty_view);

        //
        // Do additional processing specific to this app widget...
        //
        
        appWidgetManager.updateAppWidget(appWidgetIds[i], rv);   
    }
    super.onUpdate(context, appWidgetManager, appWidgetIds);
}
RemoteViewsService class

As described above, your RemoteViewsService subclass provides the RemoteViewsFactory used to populate the remote collection view.

Specifically, you need to perform these steps:

  1. Subclass RemoteViewsServiceRemoteViewsService is the service through which a remote adapter can requestRemoteViews.
  2. In your RemoteViewsService subclass, include a class that implements the RemoteViewsFactory interface. RemoteViewsFactory is an interface for an adapter between a remote collection view (such as ListViewGridView, and so on) and the underlying data for that view. Your implementation is responsible for making a RemoteViews object for each item in the data set. This interface is a thin wrapper around Adapter.

The primary contents of the RemoteViewsService implementation is its RemoteViewsFactory, described below.

RemoteViewsFactory interface

Your custom class that implements the RemoteViewsFactory interface provides the app widget with the data for the items in its collection. To do this, it combines your app widget item XML layout file with a source of data. This source of data could be anything from a database to a simple array. In the StackView Widget sample, the data source is an array of WidgetItems. The RemoteViewsFactory functions as an adapter to glue the data to the remote collection view.

The two most important methods you need to implement for your RemoteViewsFactory subclass areonCreate() and getViewAt() .

The system calls onCreate() when creating your factory for the first time. This is where you set up any connections and/or cursors to your data source. For example, the StackView Widget sample uses onCreate()to initialize an array of WidgetItem objects. When your app widget is active, the system accesses these objects using their index position in the array and the text they contain is displayed

Here is an excerpt from the StackView Widget sample's RemoteViewsFactory implementation that shows portions of the onCreate() method:

class StackRemoteViewsFactory implements
RemoteViewsService.RemoteViewsFactory {
    private static final int mCount = 10;
    private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>();
    private Context mContext;
    private int mAppWidgetId;

    public StackRemoteViewsFactory(Context context, Intent intent) {
        mContext = context;
        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }

    public void onCreate() {
        // In onCreate() you setup any connections / cursors to your data source. Heavy lifting,
        // for example downloading or creating content etc, should be deferred to onDataSetChanged()
        // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
        for (int i = 0; i < mCount; i++) {
            mWidgetItems.add(new WidgetItem(i + "!"));
        }
        ...
    }
...

The RemoteViewsFactory method getViewAt() returns a RemoteViews object corresponding to the data at the specified position in the data set. Here is an excerpt from the StackView Widget sample'sRemoteViewsFactory implementation:

public RemoteViews getViewAt(int position) {
   
    // Construct a remote views item based on the app widget item XML file, 
    // and set the text based on the position.
    RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
    rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);

    ...
    // Return the remote views object.
    return rv;
}
Adding behavior to individual items

The above sections show you how to bind your data to your app widget collection. But what if you want to add dynamic behavior to the individual items in your collection view?

As described in Using the AppWidgetProvider Class, you normally use setOnClickPendingIntent() to set an object's click behavior—such as to cause a button to launch an Activity. But this approach is not allowed for child views in an individual collection item (to clarify, you could use setOnClickPendingIntent() to set up a global button in the Gmail app widget that launches the app, for example, but not on the individual list items). Instead, to add click behavior to individual items in a collection, you use setOnClickFillInIntent(). This entails setting up up a pending intent template for your collection view, and then setting a fill-in intent on each item in the collection via your RemoteViewsFactory.

This section uses the StackView Widget sample to describe how to add behavior to individual items. In theStackView Widget sample, if the user touches the top view, the app widget displays the Toast message "Touched view n," where n is the index (position) of the touched view. This is how it works:

  • The StackWidgetProvider (an AppWidgetProvider subclass) creates a pending intent that has a custom action called TOAST_ACTION.
  • When the user touches a view, the intent is fired and it broadcasts TOAST_ACTION.
  • This broadcast is intercepted by the StackWidgetProvider's onReceive() method, and the app widget displays the Toast message for the touched view. The data for the collection items is provided by theRemoteViewsFactory, via the RemoteViewsService.

Note: The StackView Widget sample uses a broadcast, but typically an app widget would simply launch an activity in a scenario like this one.

Setting up the pending intent template

The StackWidgetProvider (AppWidgetProvider subclass) sets up a pending intent. Individuals items of a collection cannot set up their own pending intents. Instead, the collection as a whole sets up a pending intent template, and the individual items set a fill-in intent to create unique behavior on an item-by-item basis.

This class also receives the broadcast that is sent when the user touches a view. It processes this event in itsonReceive() method. If the intent's action is TOAST_ACTION, the app widget displays a Toast message for the current view.

public class StackWidgetProvider extends AppWidgetProvider {
    public static final String TOAST_ACTION = "com.example.android.stackwidget.TOAST_ACTION";
    public static final String EXTRA_ITEM = "com.example.android.stackwidget.EXTRA_ITEM";

    ...

    // Called when the BroadcastReceiver receives an Intent broadcast.
    // Checks to see whether the intent's action is TOAST_ACTION. If it is, the app widget 
    // displays a Toast message for the current item.
    @Override
    public void onReceive(Context context, Intent intent) {
        AppWidgetManager mgr = AppWidgetManager.getInstance(context);
        if (intent.getAction().equals(TOAST_ACTION)) {
            int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
            int viewIndex = intent.getIntExtra(EXTRA_ITEM, 0);
            Toast.makeText(context, "Touched view " + viewIndex, Toast.LENGTH_SHORT).show();
        }
        super.onReceive(context, intent);
    }
    
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // update each of the app widgets with the remote adapter
        for (int i = 0; i < appWidgetIds.length; ++i) {
    
            // Sets up the intent that points to the StackViewService that will
            // provide the views for this collection.
            Intent intent = new Intent(context, StackWidgetService.class);
            intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
            // When intents are compared, the extras are ignored, so we need to embed the extras
            // into the data so that the extras will not be ignored.
            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
            RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
            rv.setRemoteAdapter(appWidgetIds[i], R.id.stack_view, intent);
    
            // The empty view is displayed when the collection has no items. It should be a sibling
            // of the collection view.
            rv.setEmptyView(R.id.stack_view, R.id.empty_view);

            // This section makes it possible for items to have individualized behavior.
            // It does this by setting up a pending intent template. Individuals items of a collection
            // cannot set up their own pending intents. Instead, the collection as a whole sets
            // up a pending intent template, and the individual items set a fillInIntent
            // to create unique behavior on an item-by-item basis.
            Intent toastIntent = new Intent(context, StackWidgetProvider.class);
            // Set the action for the intent.
            // When the user touches a particular view, it will have the effect of
            // broadcasting TOAST_ACTION.
            toastIntent.setAction(StackWidgetProvider.TOAST_ACTION);
            toastIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds[i]);
            intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
            PendingIntent toastPendingIntent = PendingIntent.getBroadcast(context, 0, toastIntent,
                PendingIntent.FLAG_UPDATE_CURRENT);
            rv.setPendingIntentTemplate(R.id.stack_view, toastPendingIntent);
            
            appWidgetManager.updateAppWidget(appWidgetIds[i], rv);
        }
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    }
}
Setting the fill-in Intent

Your RemoteViewsFactory must set a fill-in intent on each item in the collection. This makes it possible to distinguish the individual on-click action of a given item. The fill-in intent is then combined with thePendingIntent template in order to determine the final intent that will be executed when the item is clicked.

public class StackWidgetService extends RemoteViewsService {
    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        return new StackRemoteViewsFactory(this.getApplicationContext(), intent);
    }
}

class StackRemoteViewsFactory implements RemoteViewsService.RemoteViewsFactory {
    private static final int mCount = 10;
    private List<WidgetItem> mWidgetItems = new ArrayList<WidgetItem>();
    private Context mContext;
    private int mAppWidgetId;

    public StackRemoteViewsFactory(Context context, Intent intent) {
        mContext = context;
        mAppWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
    }

    // Initialize the data set.
        public void onCreate() {
            // In onCreate() you set up any connections / cursors to your data source. Heavy lifting,
            // for example downloading or creating content etc, should be deferred to onDataSetChanged()
            // or getViewAt(). Taking more than 20 seconds in this call will result in an ANR.
            for (int i = 0; i < mCount; i++) {
                mWidgetItems.add(new WidgetItem(i + "!"));
            }
           ...
        }
        ...
    
        // Given the position (index) of a WidgetItem in the array, use the item's text value in 
        // combination with the app widget item XML file to construct a RemoteViews object.
        public RemoteViews getViewAt(int position) {
            // position will always range from 0 to getCount() - 1.
    
            // Construct a RemoteViews item based on the app widget item XML file, and set the
            // text based on the position.
            RemoteViews rv = new RemoteViews(mContext.getPackageName(), R.layout.widget_item);
            rv.setTextViewText(R.id.widget_item, mWidgetItems.get(position).text);
    
            // Next, set a fill-intent, which will be used to fill in the pending intent template
            // that is set on the collection view in StackWidgetProvider.
            Bundle extras = new Bundle();
            extras.putInt(StackWidgetProvider.EXTRA_ITEM, position);
            Intent fillInIntent = new Intent();
            fillInIntent.putExtras(extras);
            // Make it possible to distinguish the individual on-click
            // action of a given item
            rv.setOnClickFillInIntent(R.id.widget_item, fillInIntent);
        
            ...
        
            // Return the RemoteViews object.
            return rv;
        }
    ...
    }

Keeping Collection Data Fresh

The following figure illustrates the flow that occurs in an app widget that uses collections when updates occur. It shows how the app widget code interacts with the RemoteViewsFactory, and how you can trigger updates:

One feature of app widgets that use collections is the ability to provide users with up-to-date content. For example, consider the Android 3.0 Gmail app widget, which provides users with a snapshot of their inbox. To make this possible, you need to be able to trigger your RemoteViewsFactory and collection view to fetch and display new data. You achieve this with the AppWidgetManager call notifyAppWidgetViewDataChanged(). This call results in a callback to your RemoteViewsFactory’s onDataSetChanged() method, which gives you the opportunity to fetch any new data. Note that you can perform processing-intensive operations synchronously within the onDataSetChanged() callback. You are guaranteed that this call will be completed before the metadata or view data is fetched from the RemoteViewsFactory. In addition, you can perform processing-intensive operations within the getViewAt() method. If this call takes a long time, the loading view (specified by the RemoteViewsFactory’s getLoadingView() method) will be displayed in the corresponding position of the collection view until it returns.


应用Widget是可以在其他应用程序(如主屏幕)嵌入并接受定期更新的微型应用程序的意见。这些观点在用户界面被称为小工具,你可以发布一个与应用的Widget提供商。即能持有其他应用程序的窗口小部件的应用程序组件被称为应用程序的Widget主机。下面的截图显示音乐应用的Widget。

本文介绍了如何使用应用程序的Widget提供者发布应用的Widget。为了创建自己的讨论AppWidgetHost 托管的应用程序窗口小部件,看应用的Widget主机

设计的Widget

有关如何设计你的应用程序窗口小部件的信息,请阅读窗口小部件的设计指南。

基础


要创建一个应用程序窗口小部件,您需要满足以下条件:

AppWidgetProviderInfo对象
描述元数据为应用的Widget,如在App Widget的布局,更新频率,以及AppWidgetProvider类。这应当以XML来定义。
AppWidgetProvider类的实现
定义的基本方法,让您以编程与应用程序widget界面,基于广播的事件。通过它,当应用程序的Widget被更新,启用,禁用和删除您将收到广播。
视图布局
定义了应用程序插件的初始布局,在XML中定义。

此外,还可以实现一个应用的Widget配置活动。这是一个可选 的活动,当用户将您的Widget应用程序,并允许他或她在修改创作时应用小工具设置,启动。

以下各节描述了如何设置这些组件。

在清单中声明一个应用程序窗口小部件


首先,声明AppWidgetProvider在应用程序的类 的AndroidManifest.xml文件。例如:

<receiver  android:name = "ExampleAppWidgetProvider"  > 
    <intent-filter> 
        <action  android:name = "android.appwidget.action.APPWIDGET_UPDATE"  /> 
    </intent-filter> 
    <meta-data  android:name = "android.appwidget.provider" 
               android:resource = "@xml/example_appwidget_info"  /> 
</receiver>

<接收器>元素需要 的android:名称 属性,它指定了AppWidgetProvider由应用的Widget使用。

<意图过滤器>元素必须包括 <动作> 的元素的android:名称属性。该属性指定AppWidgetProvider接受ACTION_APPWIDGET_UPDATE播出。这是你必须显式声明的唯一播出。该AppWidgetManager 自动发送所有其他App的Widget广播到AppWidgetProvider是必要的。

<元数据>元素指定 AppWidgetProviderInfo资源,需要以下属性:

添加AppWidgetProviderInfo元


AppWidgetProviderInfo一个App Widget时,基本素质定义,如最小尺寸的布局,其初始布局资源,多久更新应用程序窗口小部件,和(可选)配置活动在创建时推出。定义AppWidgetProviderInfo对象使用一个单一的XML资源 <appwidget提供商>元素,并将其保存在项目的 RES / XML / 文件夹中。

例如:

<appwidget-provider  xmlns:android = "http://schemas.android.com/apk/res/android" 
    android:minWidth = "40dp" 
    android:minHeight = "40dp" 
    android:updatePeriodMillis = "86400000" 
    android:previewImage = "@drawable/preview" 
    android:initialLayout = "@layout/example_appwidget" 
    android:configure = "com.example.android.ExampleAppWidgetConfigure"  
    android:resizeMode = "horizontal|vertical" 
    android:widgetCategory = "home_screen" > 
</appwidget-provider>

以下是摘要<appwidget提供商>属性:

  • 该值了minWidth了minHeight 属性指定应用的Widget占用的空间最小 默认。默认主页屏幕位置应用小部件在其窗口的基础上具有一个定义的高度和宽度的细胞的网格。如果一个App Widget的最小宽度或高度值不匹配的单元格的尺寸,然后应用程序窗口小部件的尺寸圆 到最接近的单元尺寸。

    查看 应用程序的Widget设计准则有关调整你的App小工具的更多信息。

    注:为了使您的应用程序窗口小部件可跨设备,你的应用程序widget的最小尺寸不应大于4×4细胞。

  • minResizeWidthminResizeHeight属性指定应用Widget的绝对最小尺寸。这些值应指定大小低于该应用的Widget会难以辨认或不可用。使用这些属性允许用户小窗口调整大小的尺寸可能比由定义的默认插件尺寸小了minWidth了minHeight属性。在推出的Android 3.1。

    查看 应用程序的Widget设计准则有关调整你的App小工具的更多信息。

  • updatePeriodMillis属性定义多久的Widget应用程序框架应要求从更新AppWidgetProvider调用 的onUpdate() 回调方法。实际更新不保证准确地出现在时间这个值,我们则建议尽可能少,也许不超过一小时一次,以节省电池。您可能还允许用户调整的频率配置,有些人可能希望有一个股票代码,以每15分钟,或者也许只有一天四次更新。

    注意:如果该设备处于睡眠状态时,它是时间的更新(如通过定义updatePeriodMillis),则该设备将依次执行更新醒来。如果不更新超过每小时一次,这大概不会引起对电池寿命显著问题。但是,如果您需要更新更频繁和/或你并不需要更新,而设备是睡着了,那么你就可以执行,而不是基于不会唤醒设备的报警的更新。要做到这一点,设置闹钟与你的AppWidgetProvider接收,使用一个Intent AlarmManager。设置报警类型要么ELAPSED_REALTIME或 RTC的,其中,当该设备是醒着将仅提供警报。然后设置updatePeriodMillis为零(“0” )。

  • initialLayout属性点来定义应用程序的Widget布局布局资源。
  • 配置属性定义了活动,当用户添加应用程序窗口小部件,为了推出他或她来配置应用程序窗口小部件的属性。这是可选的(读创建应用程序窗口小部件配置活动下文)。
  • previewImage属性指定的应用程序部件将是什么它的配置后的预览,选择应用程序窗口小部件时,用户看到。如果没有提供,用户,而不是看到你的应用程序的启动图标。该字段对应 的android:previewImage在属性<接收器> 元素中的AndroidManifest.xml文件。对于使用的详细讨论previewImage,请参阅设置预览图像。介绍了Android 3.0的。
  • autoAdvanceViewId属性指定的应用程序部件子视图应该是自动先进的部件的主机的视图ID。介绍了Android 3.0的。
  • resizeMode属性指定由一个widget可以调整的规则。您可以使用此属性使主屏幕小部件可调整大小,水平,垂直或两个轴。用户触摸按住某个小部件,以显示其缩放柄,然后拖动水平和/或垂直手柄来改变布局网格的大小。对于价值观 resizeMode属性包括“水平”,“垂直”和“无”。为调整大小水平和垂直声明一个小部件,提供值“横|纵”。在推出的Android 3.1。
  • minResizeHeight属性指定该控件可以调整的最低高度(DPS)。此字段没有影响,如果它是大于了minHeight或没有启用垂直大小调整(见resizeMode)。介绍了Android 4.0的。
  • minResizeWidth属性指定了小部件可以调整大小的最小宽度(DPS)。此字段没有影响,如果它是大于了minWidth或没有启用水平调整大小(见resizeMode)。介绍了Android 4.0的。
  • widgetCategory属性声明是否你 ​​的应用程序的Widget可以在主屏幕(上显示home_screen),锁屏(键盘锁),或两者兼而有之。只有Android的版本比5.0的支持锁屏小部件低。对于Android 5.0以上版本,只有home_screen是有效的。

AppWidgetProviderInfo类由接受属性的详细信息<appwidget提供商>元素。

创建应用程序窗口小部件布局


你必须在XML定义一个初始布局为您的应用程序窗口小部件,并将其保存在项目的 RES /布局/目录下。您可以使用下面列出的视图对象设计的App窗口小部件,但你开始设计的Widget应用程序之前,请阅读并理解 应用的Widget设计指南

创建应用程序窗口小部件的布局很简单,如果你熟悉的布局。但是,你必须要知道,应用程序的Widget布局是基于RemoteViews,这并不支持每一种布局或视图小部件。

一个RemoteViews对象(,因此,应用程序的Widget),可以支持以下布局类:

而下面的小部件类:

不支持这些类的后裔。

RemoteViews还支持ViewStub,这是一种无形的,零大小的视图,您可以使用在运行时懒洋洋地膨胀布局资源。

添加边距应用小工具

窗口小部件,一般不应延伸到屏幕边缘,不应该在视觉上与其他小部件齐平,所以你应该在你的周围小窗口框各方增加利润。

由于Android 4.0,应用小部件会自动给出的小窗口框和应用程序窗口小部件的边框为用户提供用户的主屏幕上的其他部件和图标更好地协调之间的填充。要充分利用这一强烈推荐行为的优势,设置应用程序的targetSdkVersion至14或更大。

这很容易写出具有适用于早期版本的平台,自定义边距单一的布局,并有Android 4.0及更高没有多余的边距:

  1. 设置应用程序的targetSdkVersion至14或更大。
  2. 创建一个布局,如下面的之一,它引用一个维度资源作为边距:
    <FrameLayout 
      android:layout_width = "match_parent" 
      android:layout_height = "match_parent" 
      android:padding = "@dimen/widget_margin" >
    
       <LinearLayout 
        android:layout_width = "match_parent" 
        android:layout_height = "match_parent" 
        android:orientation = "horizontal" 
        android:background = "@drawable/my_widget_background" > 
        … 
      </LinearLayout> 
    
    </FrameLayout>
  3. 创建两个维度的资源,一个在RES /价值/提供预Android 4.0的定制空间,一个在RES /值-V14 /提供Android 4.0的小部件没有微胖:

    RES /价值/ dimens.xml

    <扪 = “widget_margin” > 8DP </扪>

    RES /值-V14 / dimens.xml

    <扪 = “widget_margin” > 0dp </扪>

另一种选择是简单地建造额外的利润到您的九宫默认背景的资产,并提供不同的九补丁没有利润率API级别14或更高版本。

使用AppWidgetProvider类


AppWidgetProvider类广播接收器的方便类来处理应用程序的Widget广播延伸。在AppWidgetProvider只接收事件广播是相关的在App控件,当应用程序的Widget被更新,删除,启用和禁用等。当这些广播事件发生时,AppWidgetProvider收到以下的方法调用:

的onUpdate()
这就是所谓的更新应用程序的Widget在被定义的间隔  updatePeriodMillis 在AppWidgetProviderInfo属性(参见 添加AppWidgetProviderInfo元以上)。当用户添加应用的Widget这种方法也被称为,所以应该进行必要的设置,如定义事件处理程序的视图和启动一个临时  服务,如果有必要,。但是,如果你已经声明了一个配置活动, 不叫这种方法,当用户添加应用程序窗口小部件,但呼吁后续更新。它是配置活动时,配置完成后进行第一次更新的责任。(请参阅 创建应用程序窗口小部件配置活动下文)。
onAppWidgetOptionsChanged()
当小部件先放入这就是所谓的任何时间小部件大小。您可以使用此回调的基础上的物件的尺寸范围,以显示或隐藏的内容。您可以通过调用获得大小范围 getAppWidgetOptions() ,它返回一个  ,其中包括以下内容:

这个回调是在API级别16(是Android 4.1)出台。如果实施此回调,请确保您的应用程序不依赖于它,因为它不会对旧设备进行调用。
onDeleted(上下文,INT [])
这就是所谓的每一个App的Widget从应用的Widget主机中删除的时间。
onEnabled(上下文)
当一个实例的应用程序的widget被首次创造了这个被调用。例如,如果用户将您的Widget应用程序的两个实例,这只是所谓的第一次。如果您需要打开一个新的数据库或进行其他设置只需要为所有App控件实例出现一次,那么这是一个很好的地方去做。
onDisabled(上下文)
当你的应用的Widget的最后一个实例是从应用的Widget主机中删除这就是所谓的。这是你应该清理所做的任何工作  onEnabled(上下文),如删除临时数据库。
的onReceive(上下文,意图)
这被称为用于每个广播和上述各回调方法之前。你通常不需要,因为默认的AppWidgetProvider实现过滤所有App的Widget广播并调用上面的方法适当实现此方法。

最重要的AppWidgetProvider回调 的onUpdate() ,因为当每个应用程序窗口小部件添加到主机(除非你使用一个配置Activity)的叫法。如果你的应用程序的Widget接受任何用户交互事件,那么你需要在这个回调注册事件处理程序。如果你的应用的Widget不创建临时文件或数据库,或执行需要清理,然后其他的工作 的onUpdate()可能是你需要定义的唯一回调方法。例如,如果你想要一个应用程序widget工具点击时启动一个活动的一个按钮,你可以使用下面的实现AppWidgetProvider的:

     

        
         

        为执行属于此提供程序的每个应用程序的Widget这个循环过程
         诠释= 0 ; < Ñ ; ++) { 
            INT appWidgetId = appWidgetIds [ ]; 

            //创建一个意向推出 
               
               

            查看该应用程序插件的布局并附加上点击监听
            //到 
              


            告诉AppWidgetManager对当前应用程序窗口小部件进行更新
            appWidgetManager updateAppWidget appWidgetId 意见); 
        } 
    } 
}

这AppWidgetProvider只定义 的onUpdate() 用于定义的目的,方法的PendingIntent一个启动的活动,并与连接到App Widget的按钮setOnClickPendingIntent(INT,的PendingIntent) 。注意,它包括一个循环,通过在各个条目迭代 appWidgetIds,它是识别由该提供商创建的每个应用程序的widget ID数组。以这种方式,如果用户创建的应用程序的widget的多个实例,则它们都同时更新。但是,只有一个updatePeriodMillis时间表将用于应用程序的widget的所有实例进行管理。例如,如果更新时间表被定义为每两个小时,和App小工具的第二个实例是第一个之后添加一小时后,他们都将在由第一和第二更新所定义的周期来更新期间将被忽略(他们都会进行每两小时不每小时更新一次)。

注意:因为AppWidgetProvider是一个扩展的BroadcastReceiver,你的进程不能保证继续运行,回调方法返回后(见的BroadcastReceiver关于广播生命周期信息)。如果你的应用的Widget安装过程可能需要几秒钟(也许当执行网页请求),你需要你的进程继续,考虑入手一部服务于 的onUpdate() 方法。从服务中,您可以不用担心AppWidgetProvider逼抢由于一个执行自己的更新到App的Widget 应用程序无响应(ANR)错误。参见维基样品的AppWidgetProvider用于运行一个应用程序的Widget的例子服务

另请参阅ExampleAppWidgetProvider.java 示例类。

接收应用的Widget广播意图

AppWidgetProvider只是一个方便的类。如果您想直接接收应用的Widget广播,你可以实现自己 的BroadcastReceiver或者重写 的onReceive(上下文,意图)回调。你需要关心的意图如下:

创建应用程序窗口小部件配置活动


如果您想用户配置设置时,他或她增加了一个新的Widget应用程序,你可以创建一个应用程序的Widget配置活动。该活动 将通过应用程序的Widget主机自动启动,并允许用户在配置创建时间为App的Widget可用的设置,如应用程序的Widget颜色,尺寸,更新周期或其他功能的设置。

配置活动应该被声明为Android清单文件中的正常活动。然而,将被应用的Widget主机与推出ACTION_APPWIDGET_CONFIGURE动作,所以活动需要接受这种意图。例如:

<activity  android:name = ".ExampleAppWidgetConfigure" > 
    <intent-filter> 
        <action  android:name = "android.appwidget.action.APPWIDGET_CONFIGURE" /> 
    </intent-filter> 
</activity>

此外,活动必须在AppWidgetProviderInfo XML文件中声明,与 配置:机器人(见属性添加AppWidgetProviderInfo元以上)。例如,配置活动可以声明如下:

<appwidget-provider  xmlns:android = "http://schemas.android.com/apk/res/android" 
    ... 
    android:configure = "com.example.android.ExampleAppWidgetConfigure"  
    ... > 
</appwidget-provider>

请注意,该活动是声明的完全限定的命名空间,因为它会从你的包范围内引用。

这就是所有你需要开始使用的配置活动。现在,所有你需要的是实际的活动。有,但是,当你实现了活动的两个重要的事情要记住:

  • 该应用程序的Widget宿主调用配置活动以及配置活动应该总是返回一个结果。结果应该包括由发起的活动(保存在Intent额外的意图传递的应用程序的Widget ID EXTRA_APPWIDGET_ID)。
  • 该 的onUpdate() 方法将不会被调用创建应用程序窗口小部件时(当配置活动推出的系统将不会发送ACTION_APPWIDGET_UPDATE广播)。它是配置活动的责任从AppWidgetManager请求更新第一次创建应用程序窗口小部件时。然而, 的onUpdate() 将呼吁后续更新,它只是跳过第一次。

请参阅下一节的代码片段如何从配置返回结果和更新应用的Widget的例子。

从配置活动更新应用的Widget

当一个应用程序的Widget使用配置的活动,这是活动的责任来更新应用程序窗口小部件时配置完成。您可以直接从请求更新这么做 AppWidgetManager

下面就来正确地更新应用程序窗口小部件并关闭配置活动的程序的摘要:

  1. 首先,获得从发射活动的意图应用的Widget ID:
    Intent intent = getIntent (); 
    Bundle extras = intent . getExtras (); 
    if  ( extras !=  null )  { 
        mAppWidgetId = extras . getInt ( 
                AppWidgetManager . EXTRA_APPWIDGET_ID ,  
                AppWidgetManager . INVALID_APPWIDGET_ID ); 
    }
  2. 执行你的App小部件配置。
  3. 当配置完成后,通过调用得到AppWidgetManager的一个实例 的getInstance(上下文)
    AppWidgetManager appWidgetManager =  AppWidgetManager 的getInstance 上下文);
  4. 更新应用的Widget使用RemoteViews调用布局 updateAppWidget(INT,RemoteViews) 
    RemoteViews views =  new  RemoteViews ( context . getPackageName (), 
    R . layout . example_appwidget ); 
    appWidgetManager . updateAppWidget ( mAppWidgetId , views );
  5. 最后,创建返回意图,随着活动的结果集,并完成活动:
    Intent resultValue =  new  Intent (); 
    resultValue . putExtra ( AppWidgetManager . EXTRA_APPWIDGET_ID , mAppWidgetId ); 
    setResult ( RESULT_OK , resultValue ); 
    finish ();

提示:当您的配置活动第一次打开,设置活动结果RESULT_CANCELED。这样一来,如果用户备份出活动的到达结束之前,应用的Widget通知主机的配置被取消和App的Widget将不能添加。

ExampleAppWidgetConfigure.java 在ApiDemos示例类的例子。

设置预览图像


Android 3.0的推出previewImage领域,它指定什么样的应用程序窗口小部件看起来像一个预览。此预览被示出为从微件选择器的用户。如果没有提供这个领域,应用Widget的图标用于预览。

这是你如何指定XML此设置:

<appwidget-provider  xmlns:android = "http://schemas.android.com/apk/res/android" 
  ... 
  android:previewImage = "@drawable/preview" > 
</appwidget-provider>

为了帮助您的应用程序窗口小部件(可以指定在创建一个预览图像previewImage场),Android模拟器包括称为应用程序“窗口小部件预览”。要创建一个预览图像,启动这个应用程序,选择您的应用程序应用程序窗口小部件,并将它设置你喜欢你们的预览图像出现,然后将其保存,并将其放置在应用程序的绘图资源。

使用App窗口小部件与收藏


Android 3.0的推出应用小部件与集合。这些种类的应用程序的窗口小部件的使用RemoteViewsService来显示由遥控数据,例如从一个备份集合内容提供商。通过提供的数据RemoteViewsService 提出使用以下视图类型,我们将把为一体的应用程序部件“收集的意见:”

列表显示
这显示了垂直滚动列表项的视图。举一个例子,看看Gmail应用程序部件。
网格视图
这显示了在二维滚动网格项目的视图。举一个例子,看到书签应用部件。
StackView
一种堆叠卡片视图(有点像一个关系网,),在这里用户可以轻弹前卡上/下看到一个/下一个卡,分别为。例子包括YouTube和图书应用的部件。 
AdapterViewFlipper
适配器支持简单  ViewAnimator两个或多个视图之间动画。只有一个孩子,显示在一段时间。

如上所述,这些收集的意见显示由远程数据支持的集合。这意味着,他们使用适配器他们的用户界面绑定到他们的数据。一个适配器结合从一组数据转化为个人的个别项目视图对象。由于这些收集的意见是通过适配器支持,Android框架必须包括额外的架构,支持应用小部件的使用。在某个应用小部件的情况下,适配器被取代RemoteViewsFactory,这简直是围绕一个瘦包装适配器 接口。当集合中要求特定项目时,RemoteViewsFactory创建并返回该项目的集合作为一个RemoteViews 对象。为了在您的应用程序窗口小部件集合视图,您必须实现RemoteViewsServiceRemoteViewsFactory

RemoteViewsService是一种服务,它允许远程适配器请求RemoteViews对象。RemoteViewsFactory是一个集合视图之间的适配器的接口(如ListView控件GridView控件该视图的基础数据,等等)和。从 StackView的Widget样本,这里是你用来实现这个服务和接口的样板代码的例子:

     
    
      
          
    


    

这里包括适配器类似的方法。见StackView的Widget样本。

}

示例应用程序

本节中的代码摘录被从绘制StackView控件样品

该样本包括10次,其中显示值栈的 “0!”通过“9!”的示例应用程序部件有这些主要行为:

  • 用户可以垂直甩在应用程序插件的顶视图来显示一个或下一个视图。这是一个内置StackView行为。
  • 无需任何用户交互,应用小工具会自动通过其在序列意见的进步,像幻灯片。这是由于设置 机器人:autoAdvanceViewId =“@ ID / stack_view”在 RES / XML / stackwidgetinfo.xml文件。此设置适用于该视图的ID,在这种情况下是堆栈视图的视图ID。
  • 如果用户触摸的顶视图,该应用插件播放吐司消息“已触摸视图Ñ ”,其中 Ñ是触摸视图的索引(位置)。对于这是如何实现的更多讨论,请参阅 添加行为的个别项目

实施与应用的集合小工具

为了实现与集合的应用程序插件,你按照你会用它来实现任何应用程序插件的相同的基本步骤。以下各节介绍您需要执行来实现与集合的应用程序插件的额外步骤。

清单与集合应用小工具

除了 ​​列出的要求中声明的清单应用程序插件,使人们有可能与集合的应用程序部件绑定到你的RemoteViewsService,你必须与你的权限清单文件声明服务BIND_REMOTEVIEWS。这可以防止其他应用程序访问任意你的应用程序widget的数据。例如,创建一个使用应用程序窗口小部件时RemoteViewsService来填充集合视图,清单条目可能是这样的:

<服务 机器人:名字= “MyWidgetService” 
... 
机器人:权限= “android.permission.BIND_REMOTEVIEWS”  />

该生产线机器人:名字=“MyWidgetService” 指的是你的子类RemoteViewsService

布局与集合应用小工具

为您的应用程序部件的布局XML文件的主要要求是,它包括收集意见之一:ListView中, GridView控件StackView或 AdapterViewFlipper。这里是 widget_layout.xmlStackView窗口小部件样本

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

<FrameLayout  xmlns:android = "http://schemas.android.com/apk/res/android" 
    android:layout_width = "match_parent" 
    android:layout_height = "match_parent" > 
    <StackView  xmlns:android = "http://schemas.android.com/apk/res/android" 
        android:id = "@+id/stack_view" 
        android:layout_width = "match_parent" 
        android:layout_height = "match_parent" 
        android:gravity = "center" 
        android:loopViews = "true"  /> 
    <TextView  xmlns:android = "http://schemas.android.com/apk/res/android" 
        android:id = "@+id/empty_view" 
        android:layout_width = "match_parent" 
        android:layout_height = "match_parent" 
        android:gravity = "center" 
        android:background = "@drawable/widget_item_background" 
        android:textColor = "#ffffff" 
        android:textStyle = "bold" 
        android:text = "@string/empty_view_text" 
        android:textSize = "20sp"  /> 
</FrameLayout>

需要注意的是空的意见必须是其空视图表示空状态集合视图的兄弟姐妹。

除了 ​​布局文件为您的整个应用程序窗口小部件,您必须创建定义布局集合中的每个项目另一个布局文件(例如,每本书的藏书在布局)。例如,StackView的Widget样品仅具有一个布局文件,widget_item.xml,由于所有的项目使用相同的布局。但是 WeatherListWidget样品有两个布局文件: dark_widget_item.xmllight_widget_item.xml

对于集合应用小部件AppWidgetProvider类

与普通的应用小工具,在你的代码的大部分AppWidgetProvider子类一般进去的onUpdate() 。在实施的主要区别的onUpdate()创建具有收藏的应用程序窗口小部件时是你必须调用setRemoteAdapter() 。这告诉集合视图从哪里得到它的数据。该RemoteViewsService然后可以回到你的执行RemoteViewsFactory,和小部件能容纳相应的数据。当你调用这个方法,你必须通过指向您实现的意图RemoteViewsService并指定应用程序窗口小部件更新应用程序小部件ID。

例如,这里的StackView的Widget样本是如何实现的onUpdate()回调方法来设置RemoteViewsService为应用程序部件集合远程适配器:

公共 无效的onUpdate 上下文语境 AppWidgetManager appWidgetManager 
诠释[] appWidgetIds  { 
    //使用远程适配器更新每个应用程序的窗口小部件
     诠释=  0 ; < appWidgetIds 长度;  ++  { 
        
        //设置启动该StackViewService,这将意图
        //为这个集合的意见。
        意向意图=   意图背景下 StackWidgetService ); 
        //添加应用程序部件的ID意图 


        实例化对象RemoteViews为应用程序部件的布局。
        RemoteViews RV =  新的 RemoteViews 背景getPackageName ()- [R 布局widget_layout ); 
        //设置了RemoteViews对象使用RemoteViews适配器
        //该适配器连接
        //到。通过指定的意图RemoteViewsService 
        //这是你如何填充数据。
        RV setRemoteAdapter appWidgetIds [ ] - [R ID stack_view 意图); 
        
        //集合时没有项目时显示空视图
        / /它应该是用于实例化RemoteViews相同的布局
        。//上述目的
        RV setEmptyView ř ID stack_view ř ID empty_view ); 

        // 
        //做具体的附加 ​​处理这个程序
        
        
   
    
    
RemoteViewsService类

如上所述,你RemoteViewsService子类提供了RemoteViewsFactory用于填充远程集合视图。

具体来说,您需要执行以下步骤:

  1. 子类RemoteViewsServiceRemoteViewsService是通过一个远程适配器可以请求服务RemoteViews
  2. RemoteViewsService子类,包括实现一个类RemoteViewsFactory 接口。RemoteViewsFactory为远程集合视图之间的适配器的接口(如ListView中GridView的该视图的基础数据,等等)和。你的实现是负责制定一个RemoteViews对象数据集中的每个项目。这个接口是围绕一个瘦包装适配器

所述的主内容RemoteViewsService 实现是其RemoteViewsFactory,如下所述。

RemoteViewsFactory接口

实现您的自定义类RemoteViewsFactory 接口提供了其集合中的项目的数据应用程序部件。要做到这一点,它结合了您的应用程序部件项目XML布局文件与数据源。数据的这个源可以是来自一个数据库的任何一个简单阵列。在 StackView的Widget样本,所述数据源是一组WidgetItems。该RemoteViewsFactory 用作适配器连接到数据胶水远程采集视图。

你需要实现你的两个最重要的方法 RemoteViewsFactory 子是 的onCreate()和 getViewAt() 

该系统调用的onCreate()创建的工厂,第一次的时候。这是你设置的任何连接和/或光标到数据源。例如,StackView控件样品使用的onCreate()初始化数组WidgetItem对象。当你的应用程序widget是积极的,系统访问这些对象使用数组和它们所包含的文本中的索引位置显示

下面是从摘录StackView的Widget 样品的 RemoteViewsFactory实施,显示了部分的onCreate() 方法:

  
 
        
       
     
     

       


                
    

      
        在OnCreate()中你设置任何连接/光标到数据源。繁重,
        //例如下载或创建内容等,应推迟到onDataSetChanged()
        //或getViewAt()。。以超过20秒在此调用将导致ANR 
         诠释=  0 ; < mCount ; ++) { 
            mWidgetItems 加入 WidgetItem +  “!” )); 
        } 
        ... 
    } 
...

所述RemoteViewsFactory方法getViewAt() 返回一个RemoteViews在指定对应于数据对象位置中的数据集。下面是从摘录 StackView的Widget样品的RemoteViewsFactory 实现:

公共 RemoteViews getViewAt INT 位置 { 
   
    //构建基于应用程序部件项目XML文件远程视图项,
    //并设置基础上的文本 
      


    
    返回远程视图对象。
    返回RV ; 
}
添加行为,个别项目

上述部分介绍如何将数据绑定到你的应用程序窗口小部件的集合。但是,如果你想做的动态行为添加到您的收藏视图中的单个项目?

作为描述使用AppWidgetProvider类,通 ​​常使用setOnClickPendingIntent()来设置一个对象的点击行为,如造成一个按钮启动的活动。但是,这种做法是不允许在单独的一个集合项目子视图(澄清,你可以使用setOnClickPendingIntent()设置在启动应用程序,例如Gmail应用程序部件一个全球性的按钮,但不是各列表项)。相反,添加一个集合中点击行为向单个项目,您使用setOnClickFillInIntent() 。这就需要建立一个未决的意图模板您的收藏视图,然后对每个项目集合中通过您设置一个填空题意图RemoteViewsFactory

本节使用StackView的Widget样本来描述如何添加行为的个别项目。在StackView的Widget样品,如果用户触摸的顶视图,该应用插件播放吐司消息“已触摸视图Ñ ”,其中 Ñ是触摸视图的索引(位置)。这是它的工作原理:

  • StackWidgetProvider(一个AppWidgetProvider子类)创建了一个悬而未决的意图已调用自定义操作TOAST_ACTION
  • 当用户触摸视图,意图被触发,它广播 TOAST_ACTION
  • 此广播被截获StackWidgetProvider的 的onReceive()方法,以及应用程序插件播放 敬酒被碰查看留言。对于集合的项目中的数据是由提供RemoteViewsFactory通过,RemoteViewsService

注:StackView小部件样品使用广播,但通常一个应用程序窗口小部件只会在类似这样的情况下推出的一项活动。

设置挂起意图模板

StackWidgetProviderAppWidgetProvider子类)建立了一个悬而未决的意图。集合个人物品不能建立自己的未决意图。取而代之的是,集合作为一个整体设置了一个待处理的意图模板,并且单个项目设置填充在意图上创建一个项目逐个项目基础的独特的行为。

这个类还接收当用户触摸一个观点,即发送广播。它在处理这一事件的onReceive()方法。如果意图的行动是TOAST_ACTION,应用程序插件播放一个吐司 当前视图的消息。

     
        
        

    

    当广播接收器接收到一个Intent广播时调用。
    //检查该意图的行为是否TOAST_ACTION。如果是,应用程序部件
    //显示当前举杯消息 
    
       
         
          
            
                
             
             视图   
        
        
    
    
    
        
        与远程适配器更新每个应用程序的窗口小部件
         诠释=  0 ; < appWidgetIds 长度;  ++  { 
    
            //设置了指向将在StackViewService的意图
            //提供了这个意见 
               

            当意图相比,群众演员被忽略,所以我们需要嵌入额外
            //入数据,以使演员不会 

              

    
            当收集没有项目时显示空视图。这应该是一个同级
            的集合视图//。
            RV setEmptyView ř ID stack_view ř ID empty_view ); 

            //这部分它使项目具有个性化的行为
            //它通过设置做到这一点一个悬而未决的意图模板。集合的个人物品
            //无法建立自己的未决意图。取而代之的是,集合作为一个整体套
            //一个未决意图模板,并且单个项目设置fillInIntent 
            //上创建一个项目逐个项目基础独特的行为。
            意图toastIntent =   意图上下文 StackWidgetProvider ) ; 
            //设置为意图的动作。
            //当用户触摸的特定视图,就会产生的效果
            //广播



              
                

            

        
    
    
设置填充式意图

RemoteViewsFactory必须在集合中的每个项目设定一个填空题意图。这使得可以区分个体上点击特定项目的动作。在填充在意图然后与组合的PendingIntent以确定被点击的项目时,将要执行的最终意图模板。

     
    
      
          
    


    
        
       
     
     

       


                
    

    初始化数据集。
        公共 无效的onCreate () { 
            //在OnCreate()中设置了任何连接/光标到数据源。繁重,
            //例如下载或创建内容等,应推迟到onDataSetChanged()
            //或getViewAt()。。以超过20秒在此调用将导致ANR 
             诠释=  0 ; < mCount ; ++) { 
                mWidgetItems 加入 WidgetItem +  “!” )); 
            } 
           ... 
        } 
        ... 
    
        //数组中给定的位置(索引)一WidgetItem的,请在该项目的文本值
        //组合应用程序窗口小部件项目的XML文件来构造一个RemoteViews对象。
        公共 RemoteViews getViewAt INT 位置 { 
            //位置将总是从0至getCount将() - 1,
    
            //构建基于应用程序部件项目XML文件RemoteViews项目,并设置
            基础上,//文本 
              

    
            接下来,设置填充意图,这将被用来填补未决的意图模板
            是在设置集合视图// 
              

              

            使其能够区分个体上单击
            某一项目的//动作
            RV setOnClickFillInIntent ř ID widget_item fillInIntent ); 
        
            ... 
        
            //返回RemoteViews对象。
            返回RV ; 
        } 
    ... 
    }

保持收集数据新鲜

下图说明了发生在更新时使用集合的应用程序插件的流量。它显示了应用程序部件代码如何与交互RemoteViewsFactory,以及如何触发更新:

使用集合应用小部件的一个特点是,为用户提供了最新的内容。例如,考虑到Android 3.0的Gmail应用小工具,它为用户提供他们的收件箱的快照。要做到这一点,你需要能够触发RemoteViewsFactory和收集,以获取并显示新的数据。你与实现这一AppWidgetManager调用notifyAppWidgetViewDataChanged() 。此调用生成一个回调到您 RemoteViewsFactoryonDataSetChanged()方法,它让你有机会获取任何新数据。请注意,您可以在内部进行同步处理密集型操作 onDataSetChanged()回调。你保证,之前的元数据或显示数据是来自取出此调用将完成RemoteViewsFactory。此外,可以将内执行处理密集型操作getViewAt() 方法。如果该调用需要很长的时间,加载视图(由指定 RemoteViewsFactory的 getLoadingView()方法)将显示在集合视图,直到它返回的相应位置。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值