Android中的AppWidget

一、AppWidget简介

Widget是一种小应用程序。在Android1.5后加入了AppWidget 框架之后,开发者可以使用该框架开发Widget。AppWidget可以拖到用户的桌面进行交互,它可以在桌面指定一个空间来显示应用提供的自定义内容。

当Widget被拖到桌面上,他们被指定一个保留的空间来显示应用提供的自定义内容。用户可以通过这个widget来 和你的应用交互,例如暂停或切换歌曲。如果你有一个后台服务,你可以按照你自己的schedule更新你的widget,或者使用AppWidget framework提供的一个自动的更新机制。

在更高层次上,每个widget就是一个BroadcastReceiver,他们用XML metadata来描述widget的细节。AppWidget framework通过broadcast意图与你的widget通信,例如当需要更新的时候。Widget更新使用RemoteViews被构建和发送。这个RemoteViews被包装成一个layout和特定内容来显示到桌面上。

你可以非常容易的添加widgets到你的应用中。你需要一个XML metadata描述这个widget,包括你想在桌面上保留的区域,一个你想展示的初始的layout,和你打算何时更新。

下图显示的是一些较好的AppWidget。

图11-1 Android桌面组件示例

二、AppWidget架构

AppWidget 框架类

以下是Android官方文档对android.appwidget包的介绍,同时也是对AppWidget框架的介绍。

Contains the components necessary to create "app widgets", which users can embed in other applications (such as the home screen) to quickly access application data and services without launching a new activity.
The behavior of an app widget is published by an "app widget provider." An "app widget host" is a component that can contain app widgets (such as the Home screen).
Any application can publish app widgets (as an app widget provider). All an application needs to do to publish an app widget is provide a BroadcastReceiver that receives the ACTION_APPWIDGET_UPDATE intent and provide some metadata about the app widget. Android provides the AppWidgetProvider class, which extends BroadcastReceiver, as a convenience class to define the app widget behavrio and aid in handling the broadcasts.
App widget hosts are the containers in which widgets can be placed. Most of the look and feel details are left up to the widget hosts. For example, the home screen has one way of viewing widgets, but the lock screen could also contain widgets, and it would have a different way of adding, removing and otherwise managing widgets.

下面对框架中比较常用的类进行简单介绍:

1)AppWidgetProvider:基于BroadCast事件操作AppWidget的接口,通过它开发人员可以接收到BroadCast事件。通过实现其中的onUpdate(Context, AppWidgetManager, int[]), onDeleted(Context, int[]), onEnabled(Context) 和onDisabled(Context)方法,来实现AppWidget的功能。其中,onUpdate、onReceive是最常用到的方法,它们接收更新通知。
2)AppWidgetProvderInfo:描述AppWidget 的元数据的对象,例如大小、更新频率、初始界面和AppWidgetProvider类等信息,以XML 文件形式存在于应用的 res/xml/目录下。
3)AppWidgetManger:负责管理 AppWidget ,向 AppwidgetProvider 发送通知。
4)RemoteViews:一个可以在其他应用进程中运行的类,向 AppWidgetProvider 发送通知。

以下是Android文档中对以上各个类的介绍,为了方便大家理解,列举如下:

1)AppWidgetProvider
A convenience class to aid in implementing an AppWidget provider. Everything you can do with AppWidgetProvider, you can do with a regular BroadcastReceiver. AppWidgetProvider merely parses the relevant fields out of the Intent that is received in onReceive(Context,Intent), and calls hook methods with the received extras.
Extend this class and override one or more of the onUpdate(Context, AppWidgetManager, int[]), onDeleted(Context, int[]), onEnabled(Context) or onDisabled(Context) methods to implement your own AppWidget functionality.

2)AppWidgetProvderInfo
Describes the meta data for an installed AppWidget provider. The fields in this class correspond to the fields in the <appwidget-provider> xml tag.

3)AppWidgetManger
Updates AppWidget state; gets information about installed AppWidget providers and other AppWidget related state.

4)RemoteViews
A class that describes a view hierarchy that can be displayed in another process. The hierarchy is inflated from a layout resource file, and this class provides some basic operations for modifying the content of the inflated hierarchy.

如何使用 Widget

长按主界面,系统会弹出一个对话框,里面会有android 内置的一些桌面组件。选择“Widgets”项目如下图所示,然后会弹出系统中所有Widget项目如下图所示,选择你要创建的即可。

图11-2 长按主界面弹出菜单

图11-3 选择Widget后,弹出Widget菜单

三、AppWidget框架相关类简介

AppWidgetManger 类

AppWidgetManager作为Android平台上最主要的Widgets管理类,提供了更新AppWidget状态,获取已经安装的Appwidget提供信息和其他的相关状态。

AppWidgetManager提供的一些方法,可以绑定你的Widget,通过provider名称获取对应的id,获取一个widget provider信息等。

通常可能只使用getInstance获取一个实例,以及updateAppWidget 这个方法,需要注意的是它提供了3种重载方法,可以更新一个widget组,或通过CompoentName来识别最终的对象,同时在Widget中一般界面的显示使用了RemoteViews这个类。

1)bindAppWidgetId(int appWidgetId, ComponentName provider)
通过给定的ComponentName 绑定appWidgetId
2)getAppWidgetIds(ComponentName provider)
通过给定的ComponentName 获取AppWidgetId
3)getAppWidgetInfo(int appWidgetId)
通过AppWidgetId 获取 AppWidget 信息
4)getInstalledProviders()
返回一个List<AppWidgetProviderInfo>的信息
5)getInstance(Context context)
获取 AppWidgetManger 实例使用的上下文对象
6)updateAppWidget(int[] appWidgetIds, RemoteViews views)
通过appWidgetId 对传进来的 RemoteView 进行修改,并重新刷新AppWidget 组件
7)updateAppWidget(ComponentName provider, RemoteViews views)
通过 ComponentName 对传进来的 RemoeteView 进行修改,并重新刷新AppWidget 组件
8)updateAppWidget(int appWidgetId, RemoteViews views)
通过appWidgetId 对传进来的 RemoteView 进行修改,并重新刷新AppWidget 组件

AppWidgetProvider类

AppWidgetProvider继承自BroadcastReceiver,成为掌控Widget 广播的便捷类。 AppWidgetProvider 只接收关于Widget 的广播,比如widget 的被更新, 被删除, 被激活, 和被禁用。当这些广播事件发生时, AppWidgetProvider 接收如下方法调用:

1)onUpdate()
根据AppWidgetProviderInfo 中updatePeriodMillis 属性描述的时间间隔来调用此方法对 Widget 进行更新。该方法在用户添加 widget 时也会被调用, 所以在该方法中应该进行基本的设置, 比如定义一个View 的事件处理器和启动一个临时Service等。然而,如果你已经定义了一个配置Activity, 那么该方法就不会在用户添加时调用, 而只在更新周期中调用。 关于配置Activity的内容之后会有讲解。

2)onDeleted(Context, int[])
每当widget 从宿主中删除时,该方法会被调用。

3)onEnabled(Context)
在widget 对象第一次被创建时调用。比如,如果用户添加了两个widget 实例,该方法只调用一次。 如果你需要对所有Widget 实例只进行一次的操作,比如打开数据库或者执行其他设置,那么需要在该方法中进行设置。

4)onDisabled(Context)
当最后一个widget 实例从宿主中删除时被调用。在这里你应该清理你在 onEnabled(Context) 做过的工作,比如删除临时数据库。

5)onReceive(Context, Intent)
每个广播事件都会调用此方法,并且在上面这些方法之前调用。通常你不需要实现该方法,因为默认的 AppWidgetProvider过滤了所有Widget 广播,并且会正常的调用上面的方法。

最重要的AppWidgetProvider 回调方法是onUpdate() 因为每当 Widget 添加到宿主中时都会被调用(除非你使用了配置Activity)。如果你的Widget 接受任意的用户交互事件, 那么你需要在该回调中注册事件处理器。 如果你的widget 不会创建临时文件或数据库, 或执行需要清理的网络操作, 那么onUpdate() 可能是唯一需要定义的回调方法。比如, 如果你想要让一个带按钮的widget 当按钮被点击时加载一个Activity, 你可以使用如下的 AppWidgetProvider 实现:

[代码]java代码:

view source
print ?
01 public class ExampleAppWidgetProvider extends AppWidgetProvider {
02
03 public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
04 final int N = appWidgetIds.length;
05
06 // Perform this loop procedure for each App Widget that belongs to this provider
07 for (int i=0; i<N; i++) {
08 int appWidgetId = appWidgetIds[i];
09
10 // Create an Intent to launch ExampleActivity
11 Intent intent = new Intent(context, ExampleActivity.class);
12 PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
13
14 // Get the layout for the App Widget and attach an on-click listener
15 // to the button
16 RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
17 views.setOnClickPendingIntent(R.id.button, pendingIntent);
18
19 // Tell the AppWidgetManager to perform an update on the current app widget
20 appWidgetManager.updateAppWidget(appWidgetId, views);
21 }
22 }
23 }

这个AppWidgetProvider只定义了onUpdate()方法,目的是定义一个PendingIntent来加载一个Activity并且把Widget按钮和setOnClickPendingIntent(int,PendingIntent)方法联系起来。注意,这包含了对每个appWidgetIds入口的迭代循环,ID数组定义了每个由这个provider创建的Widget。这种方式下,如果用户创建了超过一个的Widget实例,那么他们会被同时更新。然而,只有一个updatePeriodMillis属性来管理所有的Widget实例。比如,如果更新频率定义每两小时更新一次,添加完第一个实例后,第二个Widget实例在一小时后被添加,那么他们的更新频率是以第一个实例添加到为准,第二个添加的将被忽略(他们都会在每两小时被更新一次,而不是每小时更新)。

注意:因为AppWidgetProvider是BroadcastReceiver的子类,不能保证你的进程在回调方法返回后能继续运行(参看BroadcastReceiver文档中关于广播生命周期的信息)。如果你的Widget设置进程会用时几秒钟(也许正在处理web请求)并且你需要你的进程持续运行,考虑在onUpdate()方法中启动一个Service。在该服务中,你可以对你的Widget进行更新而不需要担心AppWidgetProvider由于ApplicationNotResponding(ANR)错误引起的停止执行。

以上对AppWidgetProvider的讲解主要参考Android官方的API Guides中对App Widgets讲解的“Using the AppWidgetProvider Class”部分,参考网址:
http://developer.android.com/guide/topics/appwidgets/index.html

强烈建议需要研究AppWidget的读者仔细阅读API Guides中对App Widgets讲解,会对理解AppWidget的整体架构非常有帮助。

你可能感兴趣的:(Android中的AppWidget)