App Widgets 应用程序小部件

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 own AppWidgetHost to host app widgets, see App Widget Host.

Widget Design

For information about how to design your app widget, read the Widgets 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 AppWidgetProvideraccepts 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 the AppWidgetProviderInfo 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 or RTC, 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 PendingIntent that 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 inappWidgetIds, 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 updatePeriodMillis schedule 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 the Wiktionary 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 ownBroadcastReceiver or override the onReceive(Context, Intent) callback. The Intents you need to care about are as follows:

Pinning App Widgets


On devices running Android 8.0 (API level 26) and higher, the launchers that allow you to create pinned shortcuts also allow you to pin app widgets onto the launcher. Similar to pinned shortcuts, these pinned widgets give users access to specific tasks in your app.

In your app, you can create a request for the system to pin a widget onto a supported launcher by completing the following sequence of steps:

  1. Create the widget in your app's manifest file, as shown in the following snippet:
    <manifest>
    ...
      <application>
        ...
        <receiver android:name="MyAppWidgetProvider">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
            </intent-filter>
            <meta-data android:name="android.appwidget.provider"
                       android:resource="@xml/my_appwidget_info" />
        </receiver>
      </application>
    </manifest>
  2. Call the requestPinAddWidget() method, as shown in the following code snippet:
    AppWidgetManager mAppWidgetManager =
            context.getSystemService(AppWidgetManager.class);
    ComponentName myProvider =
            new ComponentName(context, MyAppWidgetProvider.class);
    
    if (mAppWidgetManager.isRequestPinAppWidgetSupported()) {
        // Create the PendingIntent object only if your app needs to be notified
        // that the user allowed the widget to be pinned. Note that, if the pinning
        // operation fails, your app isn't notified.
        Intent pinnedWidgetCallbackIntent = new Intent( ... );
    
        // Configure the intent so that your app's broadcast receiver gets
        // the callback successfully. This callback receives the ID of the
        // newly-pinned widget (EXTRA_APPWIDGET_ID).
        PendingIntent successCallback = PendingIntent.createBroadcast(context, 0,
                pinnedWidgetCallbackIntent);
    
        mAppWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
    }

Note: If your app doesn't need to be notified of whether the system successfully pinned a widget onto a supported launcher, you can pass in null as the third argument to requestPinAddWidget().

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 calling getInstance(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, along with EXTRA_APPWIDGET_ID, as shown in step 5 above. 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 RemoteViewsService to display collections that are backed by remote data, such as from a content provider. The data provided by the RemoteViewsService 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 an Adapter 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 aRemoteViewsFactory, 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 settingandroid:autoAdvanceViewId="@id/stack_view" in the res/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, orAdapterViewFlipper. Here is the widget_layout.xml for the StackView 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, the StackView 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 in onUpdate(). 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. The RemoteViewsService 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 the RemoteViewsService 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 request RemoteViews.
  2. In your RemoteViewsService subclass, include a class that implements the RemoteViewsFactoryinterface. 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 theStackView 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 are onCreate() 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's RemoteViewsFactory 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 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 the StackView 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 the RemoteViewsFactory, 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 its onReceive() 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 the PendingIntent 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,您可以使用App Widget提供程序发布视图。能够容纳其他App Widget的应用程序组件被称为App Widget主机。以下屏幕截图显示了音乐应用程序小部件。

本文档介绍如何使用App Widget提供程序发布App Widget。有关创建自己的AppWidgetHost 应用程序小部件的讨论,请参阅 应用程序小部件主机

小部件设计

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

基础


要创建一个App Widget,您需要以下内容:

AppWidgetProviderInfo  目的
描述App Widget的元数据,例如App Widget的布局,更新频率和AppWidgetProvider类。这应该在XML中定义。
AppWidgetProvider  类实现
定义允许您以编程方式基于广播事件与App Widget进行接口的基本方法。通过它,你将收到广播的App Widget更新,启用,禁用和删除。
查看布局
定义在XML中定义的App Widget的初始布局。

另外,您可以实施App Widget配置活动。这是一个可选项 Activity,当用户添加您的App Widget时允许他或她在创建时修改App Widget设置。

以下部分介绍如何设置每个组件。

在清单中声明App Widget


首先,AppWidgetProvider在申请AndroidManifest.xml文件中声明这个类 例如:

< 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>  
    
          
    
     
                

<receiver>元素需要 android:name 属性,该属性指定了AppWidgetProvider所使用的应用程序的widget。

<intent-filter>元素必须包含<action> 具有该android:name属性的 元素该属性指定AppWidgetProvider接受ACTION_APPWIDGET_UPDATE广播。这是您必须明确声明的唯一广播。根据需要AppWidgetManager 自动将所有其他App Widget广播发送到AppWidgetProvider。

<meta-data>元素指定的 AppWidgetProviderInfo资源,需要以下属性:

添加AppWidgetProviderInfo元数据


所述AppWidgetProviderInfo一个应用程序的widget,的基本品质定义如它的最小布局尺寸,其初始布局资源,多久更新应用窗口小部件,和(任选地)一个配置Activity推出在创建时间。使用单个<appwidget-provider>元素在XML资源中定义AppWidgetProviderInfo对象, 并将其保存在项目的 res/xml/文件夹中。

例如:

<appwidget提供商的xmlns:机器人= “http://schemas.android.com/apk/res/android” 机器人:minWidth = “40dp” 机器人:了minHeight = “40dp” 机器人:updatePeriodMillis = “86400000” 机器人:previewImage = “@ drawable / preview” android:initialLayout = “@ layout / example_appwidget” android:configure = “com.example.android.ExampleAppWidgetConfigure” android:resizeMode = “horizo​​ntal | vertical” android:widgetCategory = “home_screen” > </ appwidget提供商> 
    
    
    
    
    
    
    
    

以下是<appwidget-provider>属性的摘要

  • minWidthminHeight 属性的值指定了App Widget 默认使用的最小空间量 默认主屏幕基于具有定义的高度和宽度的单元网格来在其窗口中定位App Widgets。如果App Widget的最小宽度或高度值与单元格的尺寸不匹配,则App Widget尺寸向上舍 入到最接近的单元格尺寸。

    有关调整App Widgets的更多信息,请参阅 App Widget设计指南

    注意:要使您的应用程序小部件可跨设备移植,应用程序小部件的最小大小决不能大于4 x 4个单元格。

  • minResizeWidthminResizeHeight属性指定应用Widget的绝对最小尺寸。这些值应该指定的大小低于该App Widget将难以辨认或不可用。使用这些属性允许用户调整窗口小部件的大小,使其大小可能小于minWidthminHeight属性定义的默认窗口大小 在Android 3.1中引入。

    有关调整App Widgets的更多信息,请参阅 App Widget设计指南

  • updatePeriodMillis属性定义了App Widget框架AppWidgetProvider通过调用 onUpdate() 回调方法来请求更新的频率实际更新不能保证按照这个值准确发生,我们建议尽可能不要频繁更新 - 也许每小时不要超过一次,以节约电池。您也可以允许用户调整配置中的频率 - 有些人可能希望每15分钟更新股票代码,或者每天只能更新四次。

    注意:如果设备在进行更新时(如定义的那样updatePeriodMillis睡眠,则设备将被唤醒以执行更新。如果您每小时不更新一次以上,这可能不会导致电池寿命的重大问题。但是,如果需要更频繁地更新和/或在设备处于睡眠状态时不需要更新,则可以根据不会唤醒设备的警报来执行更新。为此,请使用“设置”来设置您的AppWidgetProvider收到的Intent的警报 AlarmManager设置闹钟类型为“ ELAPSED_REALTIME或” RTC,只有在设备唤醒时才会发出闹钟。然后设置 updatePeriodMillis为零("0")。

  • initialLayout属性指向定义App Widget布局的布局资源。
  • configure属性定义在Activity用户添加App Widget时启动,以便他或她配置App Widget属性。这是可选的(请阅读下面的创建应用程序Widget配置活动)。
  • previewImage属性指定应用程序窗口小部件配置后的外观样式的预览,用户在选择应用窗口小部件时看到的内容。如果没有提供,用户会看到您的应用程序的启动器图标。该字段对应 于文件中元素的 android:previewImage属性有关使用的更多讨论,请参阅设置预览图像在Android 3.0中引入。<receiver>AndroidManifest.xmlpreviewImage
  • autoAdvanceViewId属性指定应由widget主机自动进阶的app widget子视图的视图ID。在Android 3.0中引入。
  • resizeMode属性指定了小部件可以调整大小的规则。您可以使用此属性来调整主屏幕小部件的大小 - 水平,垂直或两个轴。用户按住一个小部件以显示其大小调整手柄,然后拖动水平和/或垂直手柄以更改布局网格上的大小。resizeMode属性的值 包括“水平”,“垂直”和“无”。要声明一个小部件可以水平和垂直调整大小,请提供值“horizo​​ntal | vertical”。在Android 3.1中引入。
  • minResizeHeight属性指定小部件可以调整到的最小高度(以dps为单位)。如果此字段大于minHeight或未启用垂直调整大小,则此字段无效(请参阅resizeMode)。在Android 4.0中引入。
  •  minResizeWidth 属性指定了小部件可以调整到的最小宽度(以dps为单位)。如果此字段大于minWidth或未启用水平调整大小,则此字段无效(请参阅resizeMode)。在Android 4.0中引入。
  • widgetCategory属性声明您的App Widget是否可以显示在主屏幕(home_screen),锁定屏幕(keyguard)或两者上。只有低于5.0的Android版本才支持锁屏小部件。对于Android 5.0及更高版本,只有home_screen有效。

有关元素AppWidgetProviderInfo接受的属性的更多信息,请参阅<appwidget-provider>

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


您必须使用XML定义App Widget的初始布局,并将其保存在项目的 res/layout/目录中。您可以使用下面列出的View对象来设计您的App Widget,但在开始设计App Widget之前,请阅读并理解 App Widget设计指南

如果您熟悉布局,创建App Widget布局很简单但是,您必须知道,App Widget布局是基于RemoteViews,不支持每种布局或视图窗口小部件。

RemoteViews对象(以及因此的App Widget)可以支持以下布局类:

以下小部件类:

这些类的后代不支持。

RemoteViews还支持ViewStub,这是一个不可见的,零大小的视图,您可以使用它在运行时延迟布局资源。

为应用小部件添加边距

小部件通常不应该扩展到屏幕边缘,并且不应该在视觉上与其他小部件齐平,所以您应该在小部件框架的周围添加边距。

从Android 4.0开始,应用程序窗口小部件会自动在窗口小部件框架和应用程序窗口小部件的边界框之间填充,以便与用户主屏幕上的其他窗口小部件和图标更好地对齐。要利用这个强烈建议的行为,请将您的应用程序的targetSdkVersion设置为14或更大。

编写一个适用于早期版本平台的自定义边距的单一布局很容易,而Android 4.0和更高版本没有额外的边距:

  1. 将您的应用程序设置targetSdkVersion为14或更大。
  2. 创建一个如下所示的布局,为其边距引用维度资源
    <的FrameLayout 机器人:layout_width = “match_parent” 机器人:layout_height = “match_parent” 机器人:填充= “@扪/ widget_margin” > <LinearLayout中机器人:layout_width = “match_parent” 机器人:layout_height = “match_parent” 机器人:取向= “水平” android:background = “@ drawable / my_widget_background” >     ... </ LinearLayout> </ FrameLayout>
      
      
      
    
      
        
        
        
        
    
      
    
    
  3. 创建两个维度资源,一个res/values/用于提供Android 4.0之前的自定义边距,另一个res/values-v14/用于为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 > 

另一种选择是在默认情况下简单地为您的九块补丁背景资产构建额外的边距,并为API级别14或更高版本提供不同的九块补丁,而无边距。

使用AppWidgetProvider类


AppWidgetProvider类广播接收器作为一个方便的类来处理应用的Widget广播延伸。AppWidgetProvider只接收与App Widget相关的事件广播,比如当App Widget被更新,删除,启用和禁用时。发生这些广播事件时,AppWidgetProvider会收到以下方法调用:

onUpdate()
这被称为以 updatePeriodMillis  AppWidgetProviderInfo中属性定义的间隔更新App Widget (请参阅上面的 添加AppWidgetProviderInfo元数据 )。当用户添加App Widget时,也会调用这个方法,所以它应该执行必要的设置,比如为Views定义事件处理程序,并 Service 在必要时启动一个临时的 但是,如果您声明了配置Activity, 在用户添加App Widget时不会调用此方法,但会为后续更新调用此方法配置完成后,执行第一次更新是配置活动的责任。(请参阅下面的 创建应用程序小部件配置活动 。)
onAppWidgetOptionsChanged()
这是在小部件第一次放置时以及小部件被调整大小时调用的。您可以使用此回调来显示或隐藏基于窗口小部件大小范围的内容。您通过调用来获取大小范围 getAppWidgetOptions() ,返回的值  Bundle 包括以下内容:

此回调是在API级别16(Android 4.1)中引入的。如果您实现此回调,请确保您的应用程序不依赖它,因为它不会在较旧的设备上调用。
onDeleted(Context, int[])
每当从App Widget主机中删除App Widget时,都会调用它。
onEnabled(Context)
这是第一次创建App Widget的实例时调用的。例如,如果用户添加了App Widget的两个实例,这只是第一次调用。如果您需要打开一个新的数据库或执行其他设置,只需要为所有App Widget实例执行一次,那么这是一个很好的选择。
onDisabled(Context)
当您的App Widget的最后一个实例从App Widget主机中被删除时,这被调用。这是你应该清理任何工作  onEnabled(Context) ,如删除临时数据库。
onReceive(Context, Intent)
这被称为每个广播和每个上述回调方法之前。您通常不需要实现此方法,因为默认的AppWidgetProvider实现会过滤所有App Widget广播,并根据需要调用上述方法。

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

public class ExampleAppWidgetProvider extends AppWidgetProvider { public void onUpdate Context context AppWidgetManager appWidgetManager int [] appWidgetIds { final int N = appWidgetIds 长度; //执行对于属于此提供各应用程序的widget这个循环程序诠释= 0 ; < Ñ ; ++){     

        
         

        
          
            int appWidgetId = appWidgetIds [ i ]; //创建一个Intent推出为ExampleActivity 意图意图= 意图上下文为ExampleActivity ); PendingIntent pendingIntent = PendingIntent getActivity context 0 intent 0 ); //获取App Widget的布局,并将一个单击监听器//添加到按钮RemoteViews views = new

            
               
               

            
            
              RemoteViews 上下文getPackageName (),- [R 布局appwidget_provider_layout ); 
            意见setOnClickPendingIntent ř ID 按钮的PendingIntent ); //告诉AppWidgetManager在当前的app小部件            appWidgetManager 上执行更新updateAppWidget appWidgetId views ); } } }

            

        
    

这个AppWidgetProvider只 onUpdate() 定义了一个方法来定义一个PendingIntent启动Activity并附加到App Widget的按钮setOnClickPendingIntent(int, PendingIntent)请注意,它包含一个循环遍历每个条目 appWidgetIds,这是一个ID数组,标识由此提供者创建的每个App Widget。这样,如果用户创建了多个App Widget的实例,那么它们都是同时更新的。但是,只有一个updatePeriodMillis时间表将被管理的所有应用程序小部件的实例。例如,如果更新时间表定义为每两个小时,并且在第一个小时之后一个小时添加App Widget的第二个实例,则它们将在由第一个和第二个更新定义的时间段期间将被忽略(他们将每两小时更新一次,而不是每一小时)。

注意:因为AppWidgetProvider是扩展名BroadcastReceiver,所以在回调方法返回后,您的进程不保证继续运行(请参阅BroadcastReceiver有关广播生命周期的信息)。如果您的App Widget安装过程可能需要几秒钟(可能在执行Web请求时),并且您需要继续进行,请考虑Service在该onUpdate() 方法中启动一个从服务内部,您可以执行您自己的App Widget更新,而不用担心由于Application Not Responding(ANR)错误导致AppWidgetProvider关闭请参阅Wiktionary示例的AppWidgetProvider,以获取运行a的App Widget示例Service

另请参阅ExampleAppWidgetProvider.java 示例类。

接收App Widget广播意图

AppWidgetProvider只是一个便利的班级。如果您想直接接收App Widget广播,则可以实现您自己的 BroadcastReceiver或覆盖 onReceive(Context, Intent)回调。你需要关心的意图如下:

钉住应用程序小部件


在运行Android 8.0(API级别26)或更高版本的设备上,允许您创建固定快捷方式的启动器也允许您将应用程序控件固定到启动器上。与固定的快捷方式类似,这些固定的小部件可让用户访问应用中的特定任务。

在您的应用程序中,您可以创建一个系统请求,通过完成以下一系列步骤将小部件固定到支持的启动器上:

  1. 在应用程序的清单文件中创建小部件,如下面的代码片段所示:
    <manifest> 
    ... 
      <application> 
        ... 
        <receiver android:name = “MyAppWidgetProvider” > <intent-filter> <action android:name = “android.appwidget.action.APPWIDGET_UPDATE” /> </ intent-filter> <meta-data android:name = “android.appwidget.provider” android:resource = “@ xml / my_appwidget_info” /> </ receiver> </ application> </ manifest> 
            
                  
            
             
                        
        
      
    
  2. 调用该 requestPinAddWidget()方法,如以下代码片段所示:
    AppWidgetManager mAppWidgetManager =
            context.getSystemService(AppWidgetManager.class);
    ComponentName myProvider =
            new ComponentName(context, MyAppWidgetProvider.class);
    
    if (mAppWidgetManager.isRequestPinAppWidgetSupported()) {
        // Create the PendingIntent object only if your app needs to be notified
        // that the user allowed the widget to be pinned. Note that, if the pinning
        // operation fails, your app isn't notified.
        Intent pinnedWidgetCallbackIntent = new Intent( ... );
    
        // Configure the intent so that your app's broadcast receiver gets
        // the callback successfully. This callback receives the ID of the
        // newly-pinned widget (EXTRA_APPWIDGET_ID).
        PendingIntent successCallback = PendingIntent.createBroadcast(context, 0,
                pinnedWidgetCallbackIntent);
    
        mAppWidgetManager.requestPinAppWidget(myProvider, null, successCallback);
    }

注意:如果您的应用程序不需要通知系统是否成功地将小部件固定到受支持的启动器上,则可以将其null作为第三个参数 传入requestPinAddWidget()

创建一个App Widget配置活动


如果您希望用户在添加新App Widget时配置设置,则可以创建App Widget配置活动。Activity 将由App Widget主机自动启动,并允许用户在创建时配置App Widget的可用设置,例如App Widget颜色,大小,更新周期或其他功能设置。

配置Activity应该在Android清单文件中声明为普通的Activity。但是,它将由App Widget主机通过ACTION_APPWIDGET_CONFIGURE动作来启动,所以Activity需要接受这个Intent。例如:

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

此外,必须在AppWidgetProviderInfo XML文件中使用android:configure属性(请参阅上面的添加AppWidgetProviderInfo元数据来声明Activity 例如,配置Activity可以像这样声明:

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

    

请注意,该活动是使用完全限定的名称空间声明的,因为它将从包的范围之外引用。

这就是您需要开始使用配置活动的全部内容。现在你需要的是实际的活动。但是,在实施“活动”时需要记住两件重要的事情:

  • App Widget主机调用配置Activity,配置Activity应始终返回结果。结果应该包括启动Activity的Intent传递的App Widget ID(保存在Intent extras中EXTRA_APPWIDGET_ID)。
  • App Widget创建时不会调用该 onUpdate() 方法(当配置Activity启动时,系统不会发送ACTION_APPWIDGET_UPDATE广播)。当App Widget第一次创建时,配置Activity的职责是从AppWidgetManager请求更新。但是, 将被要求后续更新 - 它只是第一次跳过。onUpdate()

有关如何从配置返回结果并更新App Widget的示例,请参阅以下部分中的代码片段。

从配置Activity更新App Widget

当一个App Widget使用一个配置Activity时,当配置完成时,Activity是更新App Widget的责任。您可以通过直接请求更新来完成 AppWidgetManager

以下是正确更新App Widget并关闭配置Activity的过程摘要:

  1. 首先,从启动Activity的Intent中获取App Widget ID:
    Intent intent = getIntent (); 捆绑extras = 意图getExtras (); if extras != null {     mAppWidgetId = extras getInt AppWidgetManager EXTRA_APPWIDGET_ID AppWidgetManager INVALID_APPWIDGET_ID ); }
    
       
    
                
                
    
  2. 执行你的App Widget配置。
  3. 配置完成后,调用getInstance(Context)以下命令获取AppWidgetManager的一个实例 
    AppWidgetManager appWidgetManager = AppWidgetManager getInstance context ); 
  4. RemoteViews通过调用updateAppWidget(int, RemoteViews)以下布局来 更新App Widget 
    RemoteViews 视图= RemoteViews 上下文getPackageName (),- [R 布局example_appwidget ); appWidgetManager updateAppWidget mAppWidgetId views );  
    
    
  5. 最后,创建返回意图,将其设置为活动结果,并完成活动:
    意图resultValue = 新的意图(); resultValue putExtra AppWidgetManager EXTRA_APPWIDGET_ID mAppWidgetId ); setResult RESULT_OK resultValue ); 完成();  
    
    
    

提示:首次打开您的配置活动时,将活动结果设置为RESULT_CANCELED,连同EXTRA_APPWIDGET_ID,如上面的步骤5所示。这样,如果用户在到达结尾之前退出Activity,则会通知App Widget主机取消配置,并且不会添加App Widget。

以ApiDemos中ExampleAppWidgetConfigure.java示例类为例。

设置预览图像


Android 3.0引入了该previewImage字段,该字段指定了应用程序小部件外观的预览。这个预览会从窗口部件选择器向用户显示。如果未提供此字段,则应用程序小部件的图标用于预览。

这是你如何在XML中指定这个设置:

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

  

为了帮助为您的应用程序小部件创建预览图像(在previewImage字段中指定),Android模拟器包含一个名为“小部件预览”的应用程序。要创建预览图像,请启动此应用程序,为应用程序选择应用程序小部件,并设置预览图像的显示方式,然后将其保存并放入应用程序的可绘制资源中。

与集合使用应用程序窗口小部件


Android 3.0引入了应用程序小部件和集合。这些类型的App Widget使用RemoteViewsService显示由远程数据(例如来自内容提供者)支持的集合RemoteViewsService 应用程序小部件提供的数据使用以下视图类型之一,我们将其称为“集合视图:”

ListView
显示垂直滚动列表中的项目的视图。有关示例,请参阅Gmail应用程序小部件。
GridView
显示二维滚动网格中的项目的视图。有关示例,请参阅书签应用程序小部件。
StackView
一个堆叠的卡片视图(有点像rolodex),用户可以分别上下滑动前面的卡片来查看上一张/下一张卡片。示例包括YouTube和图书应用程序小部件。
AdapterViewFlipper
支持适配器的简单的  ViewAnimator 动画在两个或更多的视图之间。一次只显示一个孩子。

如上所述,这些集合视图显示由远程数据支持的集合。这意味着他们使用一个Adapter将他们的用户界面绑定到他们的数据。一个Adapter结合从一组数据转换成单独的个别项目View的对象。由于这些集合视图由适配器支持,所以Android框架必须包含额外的架构以支持其在应用程序小部件中的使用。在应用程序小部件的上下文中,Adapter被替换为a RemoteViewsFactory,这仅仅是Adapter 界面周围的一个薄包装当在集合中请求特定项目时,RemoteViewsFactory创建并将集合的项目作为RemoteViews 对象返回。为了在您的应用程序小部件中包含集合视图,您必须实现RemoteViewsServiceRemoteViewsFactory

RemoteViewsService是一种允许远程适配器请求RemoteViews对象的服务。RemoteViewsFactory是集合视图(例如ListViewGridView等)与该视图的基础数据之间的适配器的接口从 StackView Widget示例中,下面是用于实现此服务和接口的样板代码示例:

公共StackWidgetService 扩展RemoteViewsService { @覆盖公共RemoteViewsFactory onGetViewFactory 意向意图{ 返回StackRemoteViewsFactory getApplicationContext (),意向); } } StackRemoteViewsFactory 实现RemoteViewsService RemoteViewsFactory { // ...在这里包含适配器类的方法。请参阅StackView Widget示例。}     
    
      
          
    


    



示例应用程序

本节中的代码摘录来自StackView Widget示例

该样品由10个视图,其显示值的堆叠的 "0!"通过"9!"将样品应用部件有这些主要行为:

  • 用户可以垂直滑动应用程序窗口小部件中的顶视图,以显示下一个或上一个视图。这是一个内置的StackView行为。
  • 在没有任何用户交互的情况下,应用程序窗口小部件会按顺序自动前进,例如幻灯片放映。这是由于android:autoAdvanceViewId="@id/stack_view"在 res/xml/stackwidgetinfo.xml文件中的设置 该设置适用于视图ID,在这种情况下,视图ID是堆栈视图的视图ID。
  • 如果用户触摸顶视图,则应用小部件显示Toast消息“触摸视图n ”,其中 n是所触摸的视图的索引(位置)。有关如何实现的更多讨论,请参阅 将行为添加到单个项目

使用集合实现应用程序小部件

要使用集合实现应用程序窗口小部件,您需要遵循与用于实现任何应用程序窗口小部件相同的基本步骤。以下部分描述了您需要执行的附加步骤来实现具有集合的应用程序窗口小部件。

清单与集合的应用程序窗口小部件

除了在清单声明应用程序窗口小部件中列出的要求之外,为了使集合的应用程序窗口小部件可以绑定到您的应用程序窗口RemoteViewsService,您必须在清单文件中使用该许可声明该服务BIND_REMOTEVIEWS这可以防止其他应用程序自由访问您的应用程序窗口部件的数据 例如,在创建RemoteViewsService用于填充集合视图的App Widget时,清单条目可能如下所示:

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

 

该行android:name="MyWidgetService" 指的是你的子类RemoteViewsService

具有集合的应用程序小部件的布局

为您的应用程序窗口小部件的布局XML文件中的主要要求是,它包括收集意见之一:ListView, GridViewStackView,或 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:

 
    
    
     
        
        
        
        
        = “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” 机器人:重力= “中心” 机器人:背景= “@绘制/ widget_item_background” 机器人:文字颜色= “#FFFFFF” 机器人:TEXTSTYLE = “黑体” 机器人:文本= “@串/ empty_view_text” 机器人: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添加到意图的演员。        意图putExtra AppWidgetManager EXTRA_APPWIDGET_ID appWidgetIds [ ]);         意图使用setData 乌里解析意图toUri 意向URI_INTENT_SCHEME ))); //为应用程序小部件布局实例化RemoteViews对象。RemoteViews rv = 新的RemoteViews 
        


        
          上下文getPackageName (),- [R 布局widget_layout ); //设置RemoteViews对象以使用RemoteViews适配器。//此适配器通过指定的意图连接到RemoteViewsService。//这是你如何填充数据。        rv setRemoteAdapter appWidgetIds [ ],[R ID stack_view 意图); //当集合没有项目时,显示空的视图。
        
        
        
        


        
        //它应该在用于实例化上面的RemoteViews //对象的同一个布局中        rv setEmptyView ř ID stack_view - [R ID empty_view ); / / / / 做额外的处理特定于这个应用程序部件... //         appWidgetManager updateAppWidget appWidgetIds [ i ],rv ); } onUpdate 上下文appWidgetManager appWidgetIds
        


        
        
        


    
    );
}
RemoteViewsService类

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

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

  1. 子类RemoteViewsServiceRemoteViewsService是远程适配器可以通过其请求的服务RemoteViews
  2. 在你的RemoteViewsService子类中,包含一个实现RemoteViewsFactory 接口的类RemoteViewsFactory是远程集合视图(例如ListViewGridView等)与该视图的基础数据之间的适配器的接口您的实现负责为RemoteViews数据集中的每个项目创建一个对象。这个界面是一个薄薄的包装Adapter

实施的主要内容RemoteViewsService 是RemoteViewsFactory,如下所述。

RemoteViewsFactory接口

实现RemoteViewsFactory 接口的自定义类为应用程序小部件提供了集合中项目的数据。为此,它将您的应用程序窗口项目XML布局文件与数据源结合在一起。这个数据源可以是从数据库到简单数组的任何东西。在 StackView Widget示例中,数据源是一个数组WidgetItemsRemoteViewsFactory 作为将数据粘贴到远程集合视图的适配器功能。

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

系统onCreate()在首次创建工厂时调用这是您设置数据源的连接和/或游标的地方。例如,StackView Widget示例用于onCreate()初始化一个WidgetItem对象数组当您的应用程序小部件处于活动状态时,系统将使用它们在数组中的索引位置访问这些对象,并显示它们包含的文本。

下面是StackView Widget 示例 RemoteViewsFactory实现的摘录,显示了onCreate() 方法的一部分:

StackRemoteViewsFactory 实现RemoteViewsService RemoteViewsFactory { 私有静态最终诠释mCount = 10 ; private List < WidgetItem > mWidgetItems = new ArrayList < WidgetItem >(); private Context mContext ; private int mAppWidgetId ; 公共StackRemoteViewsFactory 上下文上下文意图意图  
 
        
       
     
     

       { 
        mContext = context ; 
        mAppWidgetId = 意图getIntExtra AppWidgetManager EXTRA_APPWIDGET_ID AppWidgetManager INVALID_APPWIDGET_ID ); } public void onCreate (){ //在onCreate()中设置任何连接/游标到你的数据源。举重,/ / 例如下载或创建内容等,应推迟onDataSetChanged()/ / 或getViewAt()。在这个通话中超过20秒钟将导致一个ANR。for int i。)
                
    

      
        
        
        
         = 0 ; < mCount ; ++){             mWidgetItems add new WidgetItem i + “!” )); } ... } ...  
  
        
        
    

RemoteViewsFactory方法getViewAt() 返回与数据集中RemoteViews指定position的数据对应对象以下是 StackView Widget示例RemoteViewsFactory 实现的摘录

public RemoteViews getViewAt int position { //根据应用程序构件项目XML文件构造远程视图项目,//根据位置设置文本。RemoteViews RV = RemoteViews mContext getPackageName (),- [R 布局widget_item );     rv setTextViewText [R ID widget_item mWidgetItems 得到位置)。  

    
    
      
文字); ... //返回远程视图对象。返回rv ; }

    
    
    
将行为添加到单个项目

以上部分向您展示了如何将您的数据绑定到您的应用部件集合。但是如果你想添加动态行为到你的集合视图中的单个项目呢?

使用AppWidgetProvider类所述,通常用于setOnClickPendingIntent()设置对象的单击行为,例如导致按钮启动Activity但是,这种方法不允许在个人收藏项目中的子视图(为了说明,您可以使用setOnClickPendingIntent()在Gmail应用程序小部件中设置全局按钮,例如启动应用程序,但不在单个列表项目中)。相反,要将点击行为添加到集合中的单个项目,您可以使用setOnClickFillInIntent()这需要为您的收藏视图设置待定的意图模板,然后通过您的收藏夹为收藏中的每个项目设置填充意图RemoteViewsFactory

本节使用StackView Widget示例来描述如何将行为添加到单个项目。StackView Widget示例中,如果用户触摸顶部视图,则应用小部件将显示Toast消息“触摸视图n ”,其中 n触摸视图的索引(位置)。这是如何工作的:

  • StackWidgetProvider(一个AppWidgetProvider子类)创建待意图已调用自定义操作TOAST_ACTION
  • 当用户触摸视图时,意图被触发并且广播 TOAST_ACTION
  • 这个广播由所截取StackWidgetProvider的 onReceive()方法,以及应用程序插件播放 Toast所触摸的视图的信息。收集项目的数据是由RemoteViewsFactory,通过RemoteViewsService

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

设置未决的意向模板

StackWidgetProviderAppWidgetProvider子)建立了一个悬而未决的意图。集合中的个人物品不能建立自己的未决意图。相反,集合作为一个整体建立了一个未决的意图模板,并且各个项目设置了一个填充意图,以逐个项目为基础创建独特的行为。

此类还接收用户触摸视图时发送的广播。它在它的onReceive()方法中处理这个事件如果意图的动作是 TOAST_ACTION,则应用小部件显示Toast 当前视图消息。

公共StackWidgetProvider 扩展AppWidgetProvider { 公共静态最终字符串TOAST_ACTION = “com.example.android.stackwidget.TOAST_ACTION” ; public static final String EXTRA_ITEM = “com.example.android.stackwidget.EXTRA_ITEM” ; ... //当BroadcastReceiver收到一个Intent广播时调用。//检查是否意图的动作是TOAST_ACTION。如果是,应用程序小部件//显示当前项目的Toast消息。@Override public void onReceive      
        
        

    

    
    
    
    
     上下文上下文意图意图{ AppWidgetManager mgr = AppWidgetManager getInstance context ); 如果意图的getAction ()。等号TOAST_ACTION )){ INT appWidgetId = 意图getIntExtra AppWidgetManager EXTRA_APPWIDGET_ID AppWidgetManager INVALID_APPWIDGET_ID ); int viewIndex =  
         
          
            
                
            意图getIntExtra EXTRA_ITEM 0 ); 吐司makeText 上下文“已触摸视图” + viewIndex 吐司LENGTH_SHORT )。show (); } onReceive context intent ); } @Override public void onUpdate 上下文上下文AppWidgetManager appWidgetManager int [] 
               
        
        
    

    
       appWidgetIds { //更新每个与远程适配器的应用小部件的诠释= 0 ; < appWidgetIds 长度; ++ { //设置向上指向将在StackViewService意图//提供这个集合的意见。意图意图= 意图上下文StackWidgetService );             意图putExtra AppWidgetManager  
        
            

            
            
               
EXTRA_APPWIDGET_ID appWidgetIds [ i ]); //当intents被比较时,extras被忽略,所以我们需要在数据中嵌入额外的//这样extras就不会被忽略。            意图使用setData 乌里解析意图toUri 意向URI_INTENT_SCHEME ))); RemoteViews RV = RemoteViews 上下文getPackageName (),- [R 布局widget_layout );
            
            

              
            rv setRemoteAdapter appWidgetIds [ ],[R ID stack_view 意图); //当集合没有项目时,显示空的视图。它应该是集合视图的一个兄弟            rv setEmptyView ř ID stack_view - [R ID empty_view ); //这个部分可以使项目具有个性化的行为。

            
            


            
            //这是通过设置一个未决的意图模板来实现的。集合中的个人物品//不能建立自己的未决意图。相反,整个集合设置一个未决的意图模板,并且各个项目设置一个fillInIntent //以在逐个项目的基础上创建独特的行为。意图toastIntent = 意图上下文StackWidgetProvider ); //为意图设置动作。//当用户触摸一个特定的视图时,会产生//广播TOAST_ACTION 的效果            toastIntent setAction 
            
            
            
               
            
            
            
StackWidgetProvider TOAST_ACTION ); 
            toastIntent putExtra AppWidgetManager EXTRA_APPWIDGET_ID appWidgetIds [ ]); 
            意图使用setData 乌里解析意图toUri 意向URI_INTENT_SCHEME ))); PendingIntent toastPendingIntent = PendingIntent getBroadcast 上下文0 toastIntent
              的PendingIntent FLAG_UPDATE_CURRENT );             rv setPendingIntentTemplate ř ID stack_view toastPendingIntent );             appWidgetManager updateAppWidget appWidgetIds [ i ],rv ); } onUpdate context appWidgetManager appWidgetIds ); } }
                



        
    
    
设置填充意图

RemoteViewsFactory必须为集合中的每个项目设置一个填充意图。这使得区分给定项目的单个点击动作成为可能。然后将填充意图与PendingIntent模板组合,以确定在单击项目时将执行的最终意图。

公共StackWidgetService 扩展RemoteViewsService { @覆盖公共RemoteViewsFactory onGetViewFactory 意向意图{ 返回StackRemoteViewsFactory getApplicationContext (),意向); } } StackRemoteViewsFactory 实现RemoteViewsService RemoteViewsFactory { 私有静态最终诠释mCount = 10 ;     
    
      
          
    


    
        
    private List < WidgetItem > mWidgetItems = new ArrayList < WidgetItem >(); private Context mContext ; private int mAppWidgetId ; public StackRemoteViewsFactory Context context Intent intent {         mContext = context ;         mAppWidgetId = 意图getIntExtra AppWidgetManager EXTRA_APPWIDGET_ID    
     
     

       


                AppWidgetManager INVALID_APPWIDGET_ID ); } //初始化数据集。公共无效onCreate (){ / /在onCreate()你设置任何连接/游标到您的数据源。举重,/ / 例如下载或创建内容等,应推迟onDataSetChanged()/ / 或getViewAt()。在这个通话中超过20秒钟将导致一个ANR。for int i = 0 ; i < mCount ; i ++){                 mWidgetItems 添加新的
    

    
          
            
            
            
               
 WidgetItem i + “!” )); } ... } ... //给定一个WidgetItem在数组中的位置(索引),使用该项目的文本值与应用控件项目XML文件结合来构造一个RemoteViews对象。public RemoteViews getViewAt int position { // position将始终从0到getCount() -  1. //根据应用程序窗口项目XML文件构造RemoteViews项目,并根据位置设置//文本。RemoteViews rv = 新的RemoteViews mContext  
            
           
        
        

        
        
          
            

            
            
              getPackageName (),R 布局widget_item ); 
            rv setTextViewText ř ID widget_item mWidgetItems 得到位置)。文本); //接下来,设置一个填充意图,它将被用来填充在StackWidgetProvider的集合视图中设置的未决意图模板Bundle extras = new Bundle ();             临时演员putInt StackWidgetProvider

            
            
              
EXTRA_ITEM 位置); Intent fillInIntent = new Intent ();             fillInIntent putExtras extras ); //可以区分单个点击//给定项目            rv的动作setOnClickFillInIntent ř ID widget_item fillInIntent ); ... //返回RemoteViews对象。返回rv ; } ... }
              

            
            


            

            
            
        
    
    

保持收藏数据新鲜

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

使用集合的应用程序小部件的一个功能是能够为用户提供最新的内容。例如,考虑Android 3.0 Gmail应用程序小部件,它为用户提供收件箱的快照。为了使这成为可能,您需要能够触发您的RemoteViewsFactory和收集视图来获取和显示新的数据。AppWidgetManager打电话来实现这一点notifyAppWidgetViewDataChanged()这个调用导致回调你 RemoteViewsFactoryonDataSetChanged()方法,这使你有机会获取任何新的数据。请注意,您可以在onDataSetChanged()回调中同步执行处理密集型操作 你保证这个调用将在元数据或者视图数据被提取之前完成RemoteViewsFactory另外,您可以在其中执行处理密集型操作getViewAt() 方法。如果该呼叫需要很长的时间,装载视图(由指定 RemoteViewsFactory的 getLoadingView()方法)将被显示在集合视图,直到它返回相应的位置。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值