Android学习笔记:Home Screen Widgets(1):关于Widget

何为Home Screen Widgets

Home screen Widget即称为小工具或者中文小工具,是显示在主页上的views,通过后台进程更新view的数据。

Android由AppWidgetManager来管理系统的widgets。安装apk后,会根据widget定义在widget列表中显示该Widget的名称、图标以及所占空间,在Android4.0中,以网格方式来显示,有些OEM厂商会对UI进行重新设计,widget列表的展现形式会有所不同。

我们长按widget列表中的某个widget,将其拖拽到主页上,实际上是AppWidgetManager在主页上创建该widget的一个实例(instance)。可以有多个实例,不同实例用widgetID来区分它们。

widget定义两个重要的java 类,一个是widget configurator activity,在widget实例生成时,被AppWidgetManager通过intent唤起进行初始化配置,其中action名为android.appwidget.action.APPWIDGET_CONFIGURE,这个java类是可选的,通常在此进行配置数据的输入和保存,由于数据量少,可以很方便地保存在shared preference中。如果我们创建了两个widget实例,这个配置activity会被调用两次。

一个Java类,负责管理widget的生命周期,包括当拖拽到主页时,需要更新时,以及拖入到垃圾桶时的处理。它是AppWidgetProvider的继承,本质是一个广播接收器,根据AppWidgetManager发出的广播信息,触发不同的回调函数,例如widget数据更新时间间隔(在widget定义中给出),widget实例的生成和删除,第一个widget实例的生成,最后一个widget实例的删除。

widget在页面上的生成是由AppWidgetManager根据我们在widget定义中给出的layout文件生成有关的UI,不是由我们的代码直接生成,因此我们也无法向在activity中那也直接对widget中的view进行操作,需要通过RemoteViews,提交给AppWidgetManager对某个实例进行处理。

小例子

我们将通过小例子,详细解读如何创建一个widget。小例子是一个生日提醒器。

在生成widget实例时,弹出配置activity,在activity中输入名字和出生日期,按“设置”按钮将数据保存在preference中,并关闭activity。

widget最上的view显示widget_id:名字,中间左边显示距下一次生日的天数,点击右边的view可打开某个网页,下面显示出生日期。

定义广播接收器

前面提到Widget有两个重要的java类,一个是可选的用于配置的activity,一个用于管理wdiget生命周期的广播接收器,接收器接收AppWidgetManager的广播消息,来触发各类回调函数。我们需在AndroidManifest.xml中定义这两个java类,下面给出广播接收器的类定义。

<manifest ……  >

<application …… android:label="TestWidget" ……> <!-- android:label就是widget列表中的widget名称 -->

… …

<receiver android:name=".BirthDayWidgetProvider">

<meta-data android:name="android.appwidget.provider" android:resource="@xml/birthday_widget_provider"/>

            <intent-filter>

<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>

</intent-filter>

</receiver>

</application>

</manifest>

这个类是继承android.appwidget.AppWidgetProvider,通过meta-data设置有关的参数。

这里补充一下meta-data的知识,最为常见的是采用键值对的方式,即<meta-data android:name="xxx" android:value="yyy" />,在组件中可以获得该数值,例如在activity中:

ActivityInfo actInfo = mContext.getPackageManager().getActivityInfo( getComponentName(), PackageManager.GET_META_DATA);

String msg = actInfo.metaData.getString("activity_name");

而在service,则为ServiceInfo,在application中为ApplicationInfo,在receiver中为ActivityInfo,但用getReceiverInfo, 如果需要ComponentName参数,可以用 new ComponentName(context, MyComponent.class)来获取。

我们看看android.appwidget.AppWidgetManager.java的有关代码:

/**

* Sent when it is time to update your AppWidget.

*

This may be sent in response to a new instance for this AppWidget provider having

* been instantiated, the requested {@link AppWidgetProviderInfo#updatePeriodMillis update interval} having lapsed, or the system booting.

* ……

*

* @see AppWidgetProvider#onUpdate AppWidgetProvider.onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)

*/

public static final String ACTION_APPWIDGET_UPDATE = "android.appwidget.action.APPWIDGET_UPDATE";

/**

* Field for the manifest meta-data tag.

*

* @see AppWidgetProviderInfo

*/

public static final String META_DATA_APPWIDGET_PROVIDER = "android.appwidget.provider";

在meta-data中,android.appwidget.provider为Android指定的关键字,用于在对应的resource中定义App Widget Provider信息的文件,该文件位于xml/下,本例子为res/xml/birthday_widget_provider.xml,定义widget的参数。

android.appwdiget.action.APPWIDGET_UPDATE是接收器监听AppWidgetManger的广播消息之一,其他还监听ACTION_APPWIDGET_ENABLED等等消息,但在receiver中必须指明是ACTION_APPWIDGET_UPDATE,系统才可识别出接收器实际是widget,才能在widget列表中添加该widget。其他需要监听的消息无需在此列出。

App widget provider的定义

在manifest.xml中,通过meta-data给出appwidget provider定义所在文件为xml/birthday_width_provider.xml,内容如下。

<?xml version="1.0" encoding="utf-8"?>

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"

android:minWidth="150dp"

android:minHeight="120dp"

android:updatePeriodMillis="43200000"

android:initialLayout="@layout/birday_widget"

android:configure="cn.wei.flowingflying.testwidget.ConfigBirthDayWidgetActivity"

android:previewImage="@drawable/gift"

android:resizeMode="horizontal|vertical">

</appwidget-provider>

在widget列表中显示widget的大小为3×2。在xml中,我们定义长150dp,宽120dp,实际上widget在Home Screen占据的空间是按网格计算的,每个网格为74dp×74dp,系统会分配所需容纳的网格。一般手机网格为4×4,平板为8×7。在《Pro Android》一书中给出建议为74的N倍减去2dp(适配边框),而在Android开发者网站推荐定义的min长宽为70*N-30,下面是给出的一个例子:

本例间隔时间为12小时(43200000ms)。Android强烈建议1天最多只有几次,不要太多。从Android2.0开始,最小值为30分钟。如果我们设置为0,表示不会自动update,我们可以通过AlarmManager类来自行控制何时update。作为实验小例子,可以改为1小时,但不能设置太短,例如1分钟,在模拟器的实验中,如果时间间隔太短是不会进行触发的。

从SDK3.1开始,用户长按widget,可以resize widget,包括horizontal,vertical和none。要能够resize,要求layout参数可伸缩,注意,如果size改变是没有callback提醒的。 具体如何resize不太明确。

previewImage是在widget list的图标,如果没有这项,实用manifest文件中定义的main icon。widget列表中的显示也称为preview。

配置Activity的定义

在appwidget-provider中通过android:configure定义配置的java类ConfigBirthDayWidgetActivity,这是个普通的activity,需要在AndroidManifest.xml中进行说明,并支持响应APPWIDGET_CONFIGURE action,AndroidManifest.xml的代码片段如下:

<activity android:name=".ConfigBirthDayWidgetActivity" android:label="配置生日小工具">

<intent-filter>

<action android:name="android.appwidget.action.APPWIDGET_CONFIGURE"/>

</intent-filter>

</activity>

至此,我们完成了widget的定义,即使我们没有具体编写任何的java类代码,我们仍可以将其打包,并在设备上安装。安装后在widget列表中看到我们的小例子TestWidget。

Widget的外观定义

在appwidget-provider中通过android:initialLayout定义widget的外观。相应的layout/birday_widget.xml如下:

<?xml version="1.0" encoding="utf-8"?>

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="150dp"

android:layout_height="120dp"

    android:orientation="vertical"

android:background="@drawable/box1">

<TextView android:id="@+id/bd_name"

android:layout_width="match_parent"

android:layout_height="30dp"

android:text="Anonymous"

android:background="@drawable/box1"

android:gravity="center"/>

<LinearLayout android:orientation="horizontal"

android:layout_width="match_parent"

android:layout_height="60dp">

<TextView android:id="@+id/bd_days"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:text="0"

android:gravity="center"

android:textSize="30sp"

android:layout_weight="50"/>

<TextView android:id="@+id/bd_buy"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:textSize="20sp"

android:text="Buy"

android:layout_weight="50"

android:background="#FF6633"

android:gravity="center"/>

</LinearLayout>

<TextView android:id="@+id/bd_date"

android:layout_width="match_parent"

android:layout_height="30dp"

android:text="2000/1/1"

android:background="@drawable/box1"

android:gravity="center"/>"

</LinearLayout>

和activity不同,不能直接在代码中获取view的对象并进行控制,需要通过AppWidgetManager用RemoteViews来进行间接控制。因此在widget外观定义中,view需要能支持remote view,包括FrameLayout、LinearLayout、RelativeLayout、AnalogClock、Button、Chronometer、ImageButton、ImageView、ProgressBar、TextView、ViewFlipper、ListView、GridView、StackView、AdapterViewFlipper。

Android给出widget外观设计的guideline,见http://developer.android.com/guide/practices/ui_guidelines/widget_design.html

通过android:background="@drawable/box1",可以定义外围轮廓。res/drawable/box1.xml的内容如下:

<?xml version="1.0" encoding="utf-8"?>

<shape xmlns:android="http://schemas.android.com/apk/res/android" >

<stroke android:width="4dp" android:color="#888888"/>  <!--定义边框 -->

<padding android:left="2dp" android:top="2dp" android:right="2dp" android:bottom="2dp"/>

<corners android:radius="4dp" />

</shape>

时间: 2024-11-10 01:20:26

Android学习笔记:Home Screen Widgets(1):关于Widget的相关文章

Android学习笔记:Home Screen Widgets(2):关于Widget

通过widget定义,我们在widget列表中看到了我们的TestWidget.当我们拖拽widget到主页时,假设在appwidet-provider中定义了android:configure的java类,在widget实例创建后会立即唤起配置activity. 这个activity主要完毕两个任务:1.配置初始化数据:2.将配置数据适配到widget实例中. 利用preference中存贮配置数据 widget数据能够保持在文件.Share preference,或者SQLite3中.wid

Pro Android学习笔记(一三七):Home Screen Widgets(3):配置Activity

文章转载仅仅能用于非商业性质,且不能带有虚拟货币.积分.注冊等附加条件.转载须注明出处http://blog.csdn.net/flowingflying/以及作者@恺风Wei. 通过widget定义.我们在widget列表中看到了我们的TestWidget.当我们拖拽widget到主页时.假设在appwidet-provider中定义了android:configure的java类,在widget实例创建后会立即唤起配置activity.这个activity主要完毕两个任务:1.配置初始化数据

Pro Android学习笔记(三):了解Android资源(上)

在Android开发中,资源包括文件或者值,它们和执行应用捆绑,无需在源代码中写死,因此我们可以改变或替换他们,而无需对应用重新编译. 了解资源构成 参考阅读Android学习笔记(三八):资源resource(上).XML解析(XmlPullParser),Android学习笔记(三九):资源resource(下). Strings资源.位于res/values下,可以有一个或多个xml文件.其中最为常见的是strings.xml,对于demo这类小例子,为了方便常全部都放在strings.x

【转】Pro Android学习笔记(四):了解Android资源(下)

处理任意的XML文件 自定义的xml文件放置在res/xml/下,可以通过R.xml.file_name来获取一个XMLResourceParser对象.下面是xml文件的例子: <rootname="tom"><--也可以是<root>,本次采用带参数的方式作为实验-->    <leaf>Hello from an elementtest.</leaf>   <leaf>Hello World!</lea

【转】Pro Android学习笔记(三):了解Android资源(上)

在Android开发中,资源包括文件或者值,它们和执行应用捆绑,无需在源代码中写死,因此我们可以改变或替换他们,而无需对应用重新编译. 了解资源构成 参考阅读Android学习笔记(三八):资源resource(上).XML解析(XmlPullParser),Android学习笔记(三九):资源resource(下). Strings资源.位于res/values下,可以有一个或多个xml文件.其中最为常见的是strings.xml,对于demo这类小例子,为了方便常全部都放在strings.x

Android学习笔记——关于onConfigurationChanged

从事Android开发,免不了会在应用里嵌入一些广告SDK,在嵌入了众多SDK后,发现几乎每个要求在AndroidManifest.xml申明Activity的广告SDK都会要求加上注明这么一句属性: android:configChanges="orientation|keyboard|keyboardHidden" 通过查阅Android API可以得知android:onConfigurationChanged实际对应的是Activity里的onConfigurationChan

Android学习笔记18:自定义Seekbar拖动条式样

Android学习笔记18:自定义Seekbar拖动条式样

Pro Android学习笔记(三三):Menu(4):Alternative菜单

什么是Alternative menu(替代菜单) 举个例子,Activity显示一个文本文件.如果用户想对文本文件进行编辑,Activity不提供编辑能力,但可由其他activity或者其他应用提供.我们将相关信息存储在一个intent中,例如该文本的Uri.这个intent可以匹配系统的多个应用,替代菜单将这些应用一一列出,菜单项的title就是该可被调用的activity的名字,图标也为该可被调用的activity的图表. 小例子说明 我们通过一个小例子进行学习,简单地打开一个URL:we

Android学习笔记(二二): 多页显示-Tag的使用

在手机屏幕中,Tab也是比较常用的,通常和List结合,例如我们手机的通信录.下面是Tag的结构. TabHost是整个Tab的容器,包括两部分,TabWidget和FrameLayout.TabWidget就是每个tab的标签,FrameLayout则是tab内容. 如果我们使用extends TabAcitivty,如同ListActivity,TabHost必须设置为@android:id/tabhost TabWidget必须设置android:id为@android:id/tabs F

android学习笔记--android启动过程之init.rc文件浅析

1.  init.rc文件结构文件位置:init.c  : /system/core/initinit.rc  : /system/core/rootdir 首先init.rc文件是以模块为单位的,每个模块里的内容都是一起执行的,模块分为3种类型:on.service.import.我们可以看下init.rc文件是怎么写的:1.import import /init.usb.rc import /init.${ro.hardware}.rc import /init.trace.rc 上面的内容