安卓:App Widget应用程序小组件(一)

App Widgets 应用程序小组件(一)


关键的类

  1. AppWidgetProvider
  2. AppWidgetProviderInfo
  3. AppWidgetManager

应用程序小组件是最小的能够嵌入到其他应用程序的应用程序Views,它能接收周期性的更新。这些Views以小组件的形式进行交付,你可以以一个应用程序小组件提供者的形式发布。能够持有App Widgets的应用程序被称作App Widget host.下面是音乐小组件的快照:

本文主要讨论"应用程序小组件提供者"(App Widget provider)。

Widget Design

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

The Basics 基础

为了创建一个 App Widget,你需要这样做:

AppWidgetProviderInfo 对象
  描述App widget 的元数据,例如他的布局,更新频率,AppWidgetProvider 类。这些都应该在XML文件中定义。

AppWidgetProvider 类的实现
  定义了基本的接口,允许你使用基于广播事件的方式编程。通过它,你能接收到App Widget的更新,使能,失效,删除。

View layout
视图布局定义了关于App Widget的原始布局。
此外,你可以实现一个App Widget配置Activity。 这是个可选的Activity,它允许在创建App Widget时修改设置。 
下面的章节描述了如何构建小组件。

Declaring an App Widget in the Manifest

在配置文件中声明App Widget。

*译者提示:关键的几个注意点(1)(2)(3)

(1)指定AppWidgetProvider对象(实际就是一个广播接收器) 标签项name所指:

ExampleAppWidgetProvider

(2)指定AppWidgetProviderInfo对象(配置信息)

通过android.appwidget.provider,确定其是ProviderInfo类型

android.appwidget.provider

指定该对象对应的XML文件位置(显示在桌面上的widget的布局文件)

@xml/example_appwidget_info

(3)指定广播更新的类型:WIDGET UPDATE

android.appwidget.action.APPWIDGET_UPDATE

下面是译文:

首先,在应用程序的AndroidManifest文件中声明AppWidgetProvider类。

 android:name="ExampleAppWidgetProvider" >
    
         android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    
     android:name="android.appwidget.provider"
               android:resource="@xml/example_appwidget_info" />

元素 需要android:name属性,它指定了小组件的AppWidgetProvider。

元素必须包括元素,而元素必定含有 android:name 属性。这个属性指定了AppWidgetProvider接收ACTION_APPWIDGET_UPDATE广播。这是唯一必须显式声明的广播, AppWidgetManager 自动发送其他种类的小组件广播给AppWidgetProvider

元素指定了AppWidgetProviderInfo资源,并需要如下属性:

  • android:name - 指定元数据的名字. 使用 android.appwidget.provider 来识别数据 作为AppWidgetProviderInfo 描述符.
  • android:resource - 指定 AppWidgetProviderInfo 资源位置.

增加 AppWidgetProviderInfo 元数据

它定义了一些必要的属性,例如最小布局尺寸,原始布局资源,更新周期,创建时的配置Activity(可选)。在XML中定义AppWidgetProviderInfo对象应当使用元素,并保存在工程的res/xml/文件夹中。

举例如下:

 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|keyguard"
    android:initialKeyguardLayout="@layout/example_keyguard">

下面是属性的总结:

  • 属性minWidth 和 minHeight 指定了小组件默认情况下消耗的空间。
  • 属性minResizeWidth 和 minResizeHeight指定了绝对最小值,小于此值将导致无效。使用时,应当小于minWidth 和 minHeight属性。
  • 属性updatePeriodMillis指定了小组件框架通过调用onUpdate()回调方法来更新AppWidgetProvider的时间。
  • 属性initialLayout指定了App Widget布局资源.
  • 属性configure指定了App Widget创建时可选的Activity,它可用于设置小组件.
  • 属性autoAdvanceViewId设置后,组件持有者会自动为子视图增加ID。在安卓3.0引入。
  • 属性resizeMode 指定了小组件调整大小的规则。你使用这个属性来使得桌面小组件能够被调整大小——横向的,纵向的,或者两者皆可。在安卓3.1版本引入。
  • 属性minResizeHeight指了组件被重调大小的最小高度值。安卓4.0引入。
  • 属性minResizeWidth 指了组件被重调大小的最小宽度值。安卓4.0引入。
  • 属性widgetCategory 声明你的小组件能否显示在桌面,或者锁屏,或者两者中。安卓4.2引入。
  • 属性initialKeyguardLayout 指定了定义在锁屏中的小组件的布局。安卓4.2引入。
  • 注意:如果设备在更新时,正处于睡眠状态,那么设备将被唤醒来执行更新。如果更新时间超过一小时,那么这不会对电池构成显著的影响。如果你需要更高频率的更新,且不需要在睡眠时更新,使用基于闹钟的方式。使用AlarmManager,在AppWidgetProvider中设定Intent.使用 ELAPSED_REALTIME 或者 RTC 闹钟类型都可以,它只会在设备醒着的时候才驱动闹铃。这时,设定updatePeriodMillis为0(zero).

Creating the App Widget Layout 创建小组件布局


你应该定义一个初始的布局XML文件,并保存在res/layout/目录下。你可以使用下面的View.在你开始设计之前,你必须阅读,并理解App Widget Design Guidelines.

如果你熟悉布局,创建小组件布局是简单的。你必须有这样一种意识:小组件是基于RemoteViews,他不支持每一种布局或者组件视图。

*译者提示:就是说你可以认为小组件是在其他的应用程序里面运行,所以它的形式受到了限制。

下面这些是支持的:

  • FrameLayout
  • LinearLayout
  • RelativeLayout
  • GridLayout

下面这些类是支持的,但是它的子类不支持:

  • AnalogClock
  • Button
  • Chronometer
  • ImageButton
  • ImageView
  • ProgressBar
  • TextView
  • ViewFlipper
  • ListView
  • GridView
  • StackView
  • AdapterViewFlipper

RemoteViews还支持 ViewStub。它是一种不可见的,0尺寸的视图,你可以在允许时膨胀它。

使用AppWidgetProvider类


AppWidgetProvider作为继承自BroadcastReceiver的便利类,它能够接受小组件广播。它只接收与其相关的广播,例如更新,删除,使能,失效。当广播事件发生时,AppWidgetProvider 接收下面这些方法的调用:

onUpdate()
经过了updatePeriodMillis间隔后,这个方法会被调用,以更新App Widget。在用户添加App Widget时,这个方法也会被调用,所以它应该执行必要的更新,例如定义View的处理函数或者开启一个临时的Service。当然,如果你定义了配置Activity,那么在添加小组件中将不会被触发,但是在随后的更新中会被调用。有必要将第一次更新的事情交给配置Activity来执行。
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:

  • OPTION_APPWIDGET_MIN_WIDTH—Contains the lower bound on the current width, in dp units, of a widget instance.
  • OPTION_APPWIDGET_MIN_HEIGHT—Contains the lower bound on the current height, in dp units, of a widget instance.
  • OPTION_APPWIDGET_MAX_WIDTH—Contains the upper bound on the current width, in dp units, of a widget instance.
  • OPTION_APPWIDGET_MAX_HEIGHT—Contains the upper bound on the current width, in dp units, of a widget instance.
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[])

App Widget被从App Widget host删除时,这个方法被调用。
onEnabled(Context)

当第一个实例被创建时调用。举个例子,如果在App Widget中有两个实例,这仅仅在第一次创建时被调用。
onDisabled(Context)

这仅仅在最后一个实例被从App Widget host移除才调用。
onReceive(Context, Intent)

任何广播都会触发此回调函数,它先于其他上面提到的回调函数。你通常不需要实现这个方法,这是因为App widget Provide的过滤机制,以及以上已经实现好的回调。

AppWidgetProvider最重要的回调方法是onUpdate(),因为你每向容器中添加一个都会触发此方法(除非你配置了“设置Activity”)。如果你接收任何的用户交互事件,那么你应该在事件处理中注册这个回调。如果你的应用程序不会创建任何临时文件后者数据库,或者其他需要被清除的任务,那么onUpdate()仅仅只是定义了的一个回调。举个例子,如果你希望点击你的widget之后,会启动一个Activity,那么你可以按照下面的实现。

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

            // 创建一个启动ExampleActivity 的 Intent ,然后用PendingIntent包装它.
            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);

            // 告诉 AppWidgetManager 对当前的Widget执行更新 onUpdate()
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

AppWidgetProvider 仅仅定义了onUpdate()方法,这是为了定义一个启动Activity的PendingIntent,并将这个PendingIntent与小组件的按钮通过方法setOnClickPendingIntent(int, PendingIntent)来进行绑定。注意到,这包含了一个迭代访问所有appWidgetIds条目的循环,这是一个包含提供者创建的小组件的ID标识符数组。在这种情况下,如果用户创建不止一个小组件实例,他们都将被同时更新。举个例子,如果更新被定为2个小时一次,第二个组件是在第一个组件添加之后添加的,那么他们将会以第一个定义的周期进行更新,第二个将被忽略(就是他们同时以两小时一次进行更新,而不是每小时)

注意:由于AppWidgetProvider扩展自BroadcastReceiver,不担保回调函数返回后,你的程序保持运行状态。如果你的小组件更新程序需要花费数秒,那么考虑在onUpdate()方法中启动一个服务。 在那个服务中,你可以执行小组件的更新,而不需要担心小组件由于 ANR错误被关闭。

你可能感兴趣的:(Android,GoogleAPI,Android,安卓,widget,桌面小组件)