Android开发指南-窗口小部件(App Widgets)

来源:互联网 发布:淘宝主图要求规范2017 编辑:程序博客网 时间:2024/06/11 14:25

应用程序窗口小部件App Widgets

应用程序窗口小部件(Widget)是微小的应用程序视图,可以被嵌入到其它应用程序中(比如桌面)并接收周期性的更新。你可以通过一个App Widget provider来发布一个Widget。可以容纳其它App Widget的应用程序组件被称为App Widget宿主。下面的截屏显示了一个音乐App Widget。

appwidget

 

 

这篇文章描述了如何使用App Widget Provider发布一个App Widget。

 

 

基础知识The Basics

为了创建一个App Widget,你需要下面这些:

AppWidgetProviderInfo 对象

描述一个App Widget元数据,比如App Widget的布局,更新频率,以及AppWidgetProvider 类。这应该在XML里定义。

AppWidgetProvider 类的实现

定义基本方法以允许你编程来和App Widget连接,这基于广播事件。通过它,当这个App Widget被更新,启用,禁用和删除的时候,你都将接收到广播通知。

视图布局

为这个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>元素接受的属性信息。

创建App Widget布局

你必须在XML中为你的App Widget定义一个初始布局并保存到项目的res/layout/ 目录下。你可以使用如下所列的视图对象来设计你的App Widget,但是在此之前,请先阅读并理解App Widget Design Guidelines.

如果你熟悉在XML中声明布局,那么创建这个App Widget布局是很简单的。但是,你必须意识到那个App Widget布局是基于RemoteViews, 这并不支持所有类型的布局或视图小部件。

一个RemoteViews对象(以及,相应的,一个App Widget)可以支持下面这个布局类:

·         FrameLayout

·         LinearLayout

·         RelativeLayout

以及下面的小部件类:

·         AnalogClock

·         Button

·         Chronometer

·         ImageButton

·         ImageView

·         ProgressBar

·         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。)

onDeleted(Context, int[])

当App Widget从宿主中删除时被调用。

onEnabled(Context)

当一个App Widget实例第一次创建时被调用。比如,如果用户添加两个你的App Widget实例,只在第一次被调用。如果你需要打开一个新的数据库或者执行其他对于所有的App Widget实例只需要发生一次的设置,那么这里是完成这个工作的好地方。

onDisabled(Context)

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

onReceive(Context, Intent)

这个接收到每个广播时都会被调用,而且在上面的回调函数之前。你通常不需要实现这个方法,因为缺省的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个意图如下:

·         ACTION_APPWIDGET_UPDATE

·         ACTION_APPWIDGET_DELETED

·         ACTION_APPWIDGET_ENABLED

·         ACTION_APPWIDGET_DISABLED

 

创建一个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 以及关闭配置活动这个过程的一个概要描述:

 

  1. 首先,从启动这个活动的意图中获取App Widget ID:
    Intent intent = getIntent(); Bundle extras = intent.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 views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget); appWidgetManager.updateAppWidget(mAppWidgetId, views);
  5. 最后,创建返回意图,设置活动结果,并结束这个活动:
    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 例子。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 cf天赋点点错了怎么办 警用记录仪丢了怎么办 被伪基站覆盖了怎么办 加热包的水喝了怎么办 剩米饭放硬了怎么办 肉罐头拉环断了怎么办 5大战区拥兵自重怎么办 买的期房停工了怎么办 怀孕后长了副乳怎么办 耳朵冻的红肿了怎么办 吃螃蟹吃柿子了怎么办 吃了螃蟹和柿子怎么办 螃蟹与柿子同吃怎么办 手被鞭炮炸伤了怎么办 索尼l36h变砖了怎么办 oppor9s手机忘记解锁图案怎么办 索尼z5刷死机了怎么办 魅蓝note3被锁定怎么办 oppo图案锁忘了怎么办 手机图案锁忘w怎么办输 手机图案解锁密码忘了怎么办 忘记htc手机锁屏怎么办 我手机密码忘了怎么办 小米5x忘记密码怎么办 oppo忘记手机解锁图案怎么办 手机解锁图案忘了怎么办 苹果id给锁了怎么办 苹果手机忘了ld怎么办 4s忘记开机密码怎么办 取卵22个肚子胀怎么办 夜神模拟器很卡怎么办 夜神模拟器卡顿怎么办 入职体检有痔疮怎么办 泰迪鼻子干怎么办恢复 泰迪幼犬鼻子干怎么办 狗狗呕吐没精神怎么办 狗狗鼻子干拉稀怎么办 狗狗鼻子干呕吐怎么办 肛门直肠环断了怎么办 原房主欠取暖费怎么办 澳门赢了几千万怎么办