http://blog.csdn.net/iefreer/article/details/4626274# java
应用程序窗口小部件App Widgetsandroid
应用程序窗口小部件(Widget)是微小的应用程序视图,能够被嵌入到其它应用程序中(好比桌面)并接收周期性的更新。你能够经过一个App Widget provider来发布一个Widget。能够容纳其它App Widget的应用程序组件被称为App Widget宿主。下面的截屏显示了一个音乐App Widget。数据库
这篇文章描述了如何使用App Widget Provider发布一个App Widget。编程
基础知识The Basics数组
为了建立一个App Widget,你须要下面这些:app
描述一个App Widget元数据,好比App Widget的布局,更新频率,以及AppWidgetProvider 类。这应该在XML里定义。ide
AppWidgetProvider 类的实现函数
定义基本方法以容许你编程来和App Widget链接,这基于广播事件。经过它,当这个App Widget被更新,启用,禁用和删除的时候,你都将接收到广播通知。oop
视图布局
为这个App Widget定义初始布局,在XML中。
另外,你能够实现一个App Widget配置活动。这是一个可选的活动Activity,当用户添加App Widget时加载并容许他在建立时来修改App Widget的设置。
下面的章节描述了如何创建这些组件:
首先,在应用程序AndroidManifest.xml文件中声明AppWidgetProvider 类,好比:
<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>
<receiver>元素须要android:name属性,它指定了App Widget使用的AppWidgetProvider 。
<intent-filter> 元素必须包括一个含有android:name属性的<action>元素。该元素指定AppWidgetProvider接受ACTION_APPWIDGET_UPDATE 广播。这是惟一你必须显式声明的广播。当须要的时候,AppWidgetManager 会自动发送全部其余App Widget广播给AppWidgetProvider。
<meta-data> 元素指定了AppWidgetProviderInfo 资源并须要如下属性:
· android:name – 指定元数据名称。
· android:resource – 指定AppWidgetProviderInfo 资源路径。
增长AppWidgetProviderInfo元数据
AppWidgetProviderInfo定义一个App Widget的基本特性,好比最小布局尺寸,初始布局资源,刷新频率,以及(可选的)建立时加载的一个配置活动。使用单独的一个<appwidget-provider>元素在XML资源里定义AppWidgetProviderInfo 对象并保存到项目的res/xml/目录下。
好比:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp" <!-- density-independent pixels -->
android:minHeight="72dp"
android:updatePeriodMillis="86400000" <!-- once per day -->
android:initialLayout="@layout/example_appwidget"
android:configure="com.example.android.ExampleAppWidgetConfigure" >
</appwidget-provider>
下面是<appwidget-provider>属性的总结:
· minWidth 和minHeight 属性的值指定了这个App Widget布局须要的最小区域。
缺省的App Widgets所在窗口的桌面位置基于有确切高度和宽度的单元网格。若是App Widget的最小长宽和这些网格单元的尺寸不匹配,那么这个App Widget将收缩到最接近的单元尺寸。(参见App Widget Design Guidelines 以获取更多关于桌面单元尺寸的信息)
由于桌面布局方向(由此,单元的尺寸)能够变化,按照拇指规则,你应该假设最坏状况单元尺寸是74像素高和宽。不过,你必须从最后的尺寸中减去2以把像素计算过程当中产生的任何的整数舍入偏差考虑在内。要找到像素密度无关的最小宽度和高度,使用这个公式:
(number of cells * 74) - 2
遵循这个公式,你应该使用72dp为每个单元高度,294dp为四个单元宽度。
· updatePerdiodMillis 属性定义了App Widget框架调用onUpdate()方法来从AppWidgetProvider请求一次更新的频度。实际更新时间并不那么精确,并且咱们建议更新频率越低越好-也许每小时不超过一次以节省电源。你也许还会容许用户在配置中调整这个频率-一些人可能想每15分钟一次股票报价,或者一天只要四次。
· initialLayout属性指向定义App Widget布局的资源。
· configure属性定义了Activity ,当用户添加App Widget时启动,觉得他或她配置App Widget特性。这是可选的(阅读下面的Creating an App Widget Configuration Activity)。
参见AppWidgetProviderInfo 类以获取更多能够被<appwidget-provider>元素接受的属性信息。
你必须在XML中为你的App Widget定义一个初始布局并保存到项目的res/layout/ 目录下。你可使用以下所列的视图对象来设计你的App Widget,可是在此以前,请先阅读并理解App Widget Design Guidelines.
若是你熟悉在XML中声明布局,那么建立这个App Widget布局是很简单的。可是,你必须意识到那个App Widget布局是基于RemoteViews, 这并不支持全部类型的布局或视图小部件。
一个RemoteViews对象(以及,相应的,一个App Widget)能够支持下面这个布局类:
以及下面的小部件类:
· Button
· TextView
不支持这些类的派生。
使用AppWidgetProvider类
你必须经过在清单文件中使用<receiver>元素来声明你的AppWidgetProvider 类实现为一个广播接收器(参见上面的Declaring an App Widget in the Manifest)。
AppWidgetProvider 类扩展BroadcastReceiver 为一个简便类来处理App Widget广播。AppWidgetProvider只接收和这个App Widget相关的事件广播,好比这个App Widget被更新,删除,启用,以及禁用。当这些广播事件发生时,AppWidgetProvider 将接收到下面的方法调用:
onUpdate(Context, AppWidgetManager, int[])
这个方法调用来间隔性的更新App Widget,间隔时间用AppWidgetProviderInfo 里的updatePeriodMillis属性定义(参见添加AppWidgetProviderInfo元数据)。这个方法也会在用户添加App Widget时被调用,所以它应该执行基础的设置,好比为视图定义事件处理器并启动一个临时的服务Service,若是须要的话。可是,若是你已经声明了一个配置活动,这个方法在用户添加App Widget时将不会被调用,而只在后续更新时被调用。配置活动应该在配置完成时负责执行第一次更新。(参见下面的建立一个App Widget配置活动Creating an App Widget Configuration Activity。)
当App Widget从宿主中删除时被调用。
当一个App Widget实例第一次建立时被调用。好比,若是用户添加两个你的App Widget实例,只在第一次被调用。若是你须要打开一个新的数据库或者执行其余对于全部的App Widget实例只须要发生一次的设置,那么这里是完成这个工做的好地方。
当你的App Widget的最后一个实例被从宿主中删除时被调用。你应该在onEnabled(Context)中作一些清理工做,好比删除一个临时的数据库。
这个接收到每一个广播时都会被调用,并且在上面的回调函数以前。你一般不须要实现这个方法,由于缺省的AppWidgetProvider 实现过滤全部App Widget 广播并恰当的调用上述方法。
注意: 在Android 1.5中, 有一个已知问题,onDeleted()方法在该调用时不被调用。为了规避这个问题,你能够像Group post中描述的那样实现onReceive() 来接收这个onDeleted()回调。
最重要的AppWidgetProvider 回调函数是onUpdated(), 由于它是在每一个App Widget添加进宿主时被调用的(除非你使用一个配置活动)。若是你的App Widget 要接受任何用户交互事件,那么你须要在这个回调函数中注册事件处理器。若是你的App Widget不建立临时文件或数据库,或者执行其它须要清理的工做,那么onUpdated() 多是你须要定义的惟一的回调函数。好比,若是你想要一个带一个按钮的App Widget,当点击时启动一个活动,你可使用下面的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);
}
}
}
这个AppWidgetProvider 仅定义了onUpdated() 方法,为了定义一个PendingIntent,来启动一个活动并使用setOnClickPendingIntent(int, PendingIntent)方法把它附着到这个App Widget的按钮上。注意它包含了一个遍历appWidgetIds中全部项的循环,这是一个IDs数组,每一个ID用来标识由这个Provider建立的一个App Widget。这样,若是用户建立多于一个这个App Widget的实例,那么它们将被同步更新。不过,对于全部的App Widget实例,只有一个updatePeriodMillis 时间表被管理。好比,若是这个更新时间表被定义为每隔两个小时,并且App Widget的第二个实例是在第一个后面一小时添加的,那么它们将按照第一个所定义的周期来更新而第二个被忽略(它们将都是每2个小时进行更新,而不是每小时)。
注意: 由于这个AppWidgetProvider 是一个广播接收器BroadcastReceiver,不能保证你的进程在回调函数返回后仍然继续运行(参见应用程序基础>广播接收器的生命周期Application Fundamentals > Broadcast Receiver Lifecycle以获取更多信息)。若是你的App Widget设置过程能持续几秒钟(也许当执行网页请求时)并且你要求你的进程继续,考虑在onUpdated()方法里启动一个服务Service。从这个服务里,你能够执行本身的App Widget更新,而没必要担忧AppWidgetProvider 因为一个应用程序无响应错误Application Not Responding (ANR)而关闭。参见Wiktionary sample's AppWidgetProvider,这是个App Widget运行一个Service的例子。
一样参见ExampleAppWidgetProvider.java 例子类。
接收App Widget广播意图
AppWidgetProvider 只是一个简便类。若是你想直接接收App Widget 广播,你能够实现本身的BroadcastReceiver 或者重写onReceive(Context, Intent) 回调函数。你须要注意的4个意图以下:
建立一个App Widget 配置活动
若是你想让用户在添加一个新的App Widget时调整设置,你能够建立一个App Widget配置活动。这个活动将被App Widget宿主自动启动并容许用户在建立时配置可用的设置,好比App Widget颜色,尺寸,更新周期或者其它功能设置。
这个配置活动应该在Android清单文件中声明为一个通用活动。不过,它将被经过ACTION_APPWIDGET_CONFIGURE活动而被App Widget宿主启动,所以这个活动须要接受这个意图。好比:
<activity android:name=".ExampleAppWidgetConfigure">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
</intent-filter>
</activity>
一样的,活动必须在AppWidgetProviderInfo XML 文件中声明,经过android:configure属性(参见上面的添加AppWidgetProviderInfo元数据Adding the AppWidgetProviderInfo Metadata)。好比,配置活动能够声明以下:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
...
android:configure="com.example.android.ExampleAppWidgetConfigure"
... >
</appwidget-provider>
注意这个活动是用全名声明的,由于它将从你的程序包外被引用。
这就是全部关于配置活动你一开始须要了解的。如今你须要一个真实的活动。这儿就有,不过,当你实现这个活动时记住两件重要的事情:
• App Widget 宿主调用配置活动并且配置活动应该老是返回一个结果.这个结果应该包含这个经过启动该活动的意图传递的App Widget ID(以EXTRA_APPWIDGET_ID保存在乎图的附加段Intent extras中)
• 当这个 App Widget 被建立时将不会调用onUpdate() 方法(当一个配置活动启动时,系统将不会发送ACTION_APPWIDGET_UPDATE广播).配置活动应该在 App Widget 第一次被建立时负责从AppWidgetManager请求一个更新.不过, onUpdate() 将在后续更新中被调用-只忽略第一次.
参见下面章节的代码片段,该示例说明了如何从配置中返回一个结果并更新这个App Widget.
从配置活动中更新一个App Widget
当一个App Widget使用一个配置活动,那么当配置结束时,就应该由这个活动来更新这个App Widget.你能够直接AppWidgetManager里请求一个更新来这么作.
下面是恰当的更新App Widget 以及关闭配置活动这个过程的一个概要描述:
首先,从启动这个活动的意图中获取App Widget ID:
Intent intent = getIntent(); Bundle extras = intent.getExtras(); if (extras != null) { mAppWidgetId = extras.getInt( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); }
实施你的App Widget 配置。
当配置完成后,经过调用getInstance(Context)获取一个AppWidgetManager实例:
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
以一个RemoteViews布局调用updateAppWidget(int, RemoteViews)更新App Widget:
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget); appWidgetManager.updateAppWidget(mAppWidgetId, views);
最后,建立返回意图,设置活动结果,并结束这个活动:
Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); setResult(RESULT_OK, resultValue); finish();
提示: 当你的配置活动第一次打开时,设置活动结果为RESULT_CANCELED。这样,若是用户在结束以前从活动外返回,这个App Widget 宿主会接收到配置取消通知而不会添加这个App Widget。
参见ApiDemos里面的ExampleAppWidgetConfigure.java 例子。