AppWidgetProvider
AppWidgetProviderInfo
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.
为了创建一个 App Widget,你需要这样做:
AppWidgetProviderInfo
对象
AppWidgetProvider
类的实现
*译者提示:关键的几个注意点(1)(2)(3)
(1)指定AppWidgetProvider对象(实际就是一个广播接收器)
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。
元素
android:name
- 指定元数据的名字. 使用 android.appwidget.provider
来识别数据 作为AppWidgetProviderInfo
描述符.android:resource
- 指定 AppWidgetProviderInfo
资源位置. 它定义了一些必要的属性,例如最小布局尺寸,原始布局资源,更新周期,创建时的配置Activity(可选)。在XML中定义AppWidgetProviderInfo对象应当使用
举例如下:
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
属性。属性resizeMode
指定了小组件调整大小的规则。你使用这个属性来使得桌面小组件能够被调整大小——横向的,纵向的,或者两者皆可。在安卓3.1版本引入。属性widgetCategory
声明你的小组件能否显示在桌面,或者锁屏,或者两者中。安卓4.2引入。initialKeyguardLayout
指定了定义在锁屏中的小组件的布局。安卓4.2引入。 注意:如果设备在更新时,正处于睡眠状态,那么设备将被唤醒来执行更新。如果更新时间超过一小时,那么这不会对电池构成显著的影响。如果你需要更高频率的更新,且不需要在睡眠时更新,使用基于闹钟的方式。使用AlarmManager,在AppWidgetProvider中设定Intent.使用 ELAPSED_REALTIME
或者 RTC
闹钟类型都可以,它只会在设备醒着的时候才驱动闹铃。这时,设定updatePeriodMillis为0(zero).
你应该定义一个初始的布局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尺寸的视图,你可以在允许时膨胀它。
使用Manifest中的
AppWidgetProvider作为继承自BroadcastReceiver的便利类,它能够接受小组件广播。它只接收与其相关的广播,例如更新,删除,使能,失效。当广播事件发生时,AppWidgetProvider 接收下面这些方法的调用:
onUpdate()
onAppWidgetOptionsChanged()
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.onDeleted(Context, int[])
onEnabled(Context)
onDisabled(Context)
onReceive(Context, Intent)
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错误被关闭。