应用程序小组件是一个微型的应用程序视图,可以嵌入其他应用程序(例如主屏幕)中并接收定期更新。本文档介绍了如何使用App Widget provider发布Android小组件。
概述
应用程序视图在用户界面中称为组件(Widget),您可以使用小组件提供程序(App Widget provider)发布这些视图。能够容纳其他小组件的应用程序组件称为App Widget宿主(如Launcher),下图为时钟和天气的小组件示例,更多有关小组件设计规范的内容,请参见 App Widgets Overview。
为了创建小组件,您还需要先了解以下信息。
AppWidgetProviderInfo
描述应用程序小组件的元数据,例如小组件的布局、更新频率、指定AppWidgetProvider类等。
AppWidgetProvider
用来处理小组件的广播事件,当更新、启用、禁用、删除小组件时,您可以收到广播。
View layout
以XML定义的小组件的初始布局
其他
还可以为您的小组件配置活动。启动活动后,允许用户在该活动里修改小组件设置。
创建小组件
在应用程序的清单文件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.appwidget.provider将数据标识为AppWidgetProviderInfo描述符。
android:resource 指定AppWidgetProviderInfo的资源位置。
添加AppWidgetProviderInfo元数据。
AppWidgetProviderInfo定义了小组件的基本配置(例如最小布局尺寸、初始布局资源、更新频率、(可选)在创建时启动的配置Activity等)。使用单个元素在XML资源中定义AppWidgetProviderInfo对象,并将其保存在项目的res/xml文件夹中。
<appwidget-provider 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"> </appwidget-provider>
代码配置说明如下。
minWidth和minHeight属性指定默认情况下App Widget占用的最小尺寸(为了使您App的小组件适配多种屏幕,此处的最小尺寸不得大于4 x 4单元)。更多信息请参见应用程序小组件设计指南。
updatePeriodMillis属性定义App Widget框架通过调用
onUpdate()
回调方法从AppWidgetProvider请求更新的频率。使用该值不能保证实际的更新会准时进行,我们不建议频繁地更新(每小时不超过一次),以便节省电池电量。initialLayout属性指向定义App Widget布局的布局资源。
configure属性(可选属性)定义了用户添加App Widget时要启动的活动,以便配置App Widget属性。
previewImage属性指定配置后的应用小组件的预览,用户在选择应用小组件时可见。如果未提供,用户看到的为您应用程序的启动器图标。
resizeMode属性指定可以调整窗口小组件大小的规则,例如水平、垂直或双向调整大小等。
minResizeHeight和minResizeWidth属性指定窗口小组件可以调整大小的最小高度与最小宽度(单位为dp)。
说明更多元素属性的介绍请参见AppWidgetProviderInfo。
创建小组件布局。
使用XML为您的小组件定义初始布局,并将其保存在工程的res/layout目录中。
小组件布局基于RemoteViews,一个RemoteViews对象(通常就是一个小组件)可以支持以下布局类和视图组件。
布局类
FrameLayout
LinearLayout
RelativeLayout
GridLayout
说明仅支持这些类,不支持这些类的子类。
视图组件
AnalogClock
Button
Chronometer
ImageButton
ImageView
ProgressBar
TextView
ViewFlipper
ListView
GridView
StackView
AdapterViewFlipper
其他
RemoteViews还支持ViewStub,这是一个不可见的零尺寸视图,可用于在运行时延迟布局资源的渲染。
下面以设计布局类FrameLayout为例介绍,更多信息请参见App Widget设计指南。
进入res/layout/目录,创建一个xml的布局文件(例如:appwidget_provider_layout.xml)。
添加布局类FrameLayout,相关代码如下。
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="OK" tools:ignore="HardcodedText" /> </FrameLayout>
添加小组件之间的距离。
为了更好地提升用户体验,从Android 4.0及以上版本,系统会自动在小组件框架和应用小组件的边界框之间提供填充。Android 4.0以下则需要开发者自行设置(由于目前市场上Android 4.0以下机型较少,此处不作介绍,可自行查找资料)。
创建AppWidgetProvider类。
最后您还需要创建在清单中声明的ExampleAppWidgetProvider类。例如,如果您想要一个用于单击的按钮小组件,使用AppWidgetProvider实现的示例代码如下。
/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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); Intent intent = new Intent(); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); // Get the layout for the App Widget and attach an on-click listener // to the button,其中appwidget_provider_layout为创建的xml布局文件名称 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仅定义
onUpdate()
方法,并定义启动活动的PendingIntent,使用setOnClickPendingIntent(int,PendingIntent)
将其添加到小组件的按钮上。关于AppWidgetProvider的使用说明如下。
AppWidgetProvider类是BroadcastReceiver 的扩展,用来处理小组件的广播。 AppWidgetProvider仅接收与小组件相关的事件广播,例如何时更新,删除,启用和禁用小组件。当发生这些广播事件时,AppWidgetProvider会收到以下方法调用:
AppWidgetProvider回调通过
onUpdate()
方法。如果您的小组件需要接受用户的交互事件(此时您需要在此回调中注册事件处理程序),并且您的小组件不需要创建临时文件或数据库,也不需要执行其他清理的工作时,您无需关心除onUpdate()
以外的生命周期回调。说明由于AppWidgetProvider是BroadcastReceiver的子类,因此不能保证您的进程在回调方法返回后仍能继续运行(有关广播生命周期的信息,请参见BroadcastReceiver)。如果您的小组件设置过程需要花费几秒钟的时间(可能是在执行Web请求时),并且您要求设置过程继续进行,请使用
onUpdate()
方法,通过在方法中启动服务来处理耗时操作。您可以从服务内部对小组件执行自己的更新,从而不必担心AppWidgetProvider会由于Application Not Responding(ANR)而关闭。
请求接口
小组件开发过程中常用到的请求接口如下。
获取设备列表(已添加到小组件)
path:/iotx/ilop/queryComponentProduct version:1.0.0 params:@{}
获取设备属性
path:/iotx/ilop/queryComponentProperty version:1.0.0 params = @{@"productKey":productKey,@"iotId":iotId,@"query":@{@"dataType":@"BOOL”, @"I18Language":@"zh-CN"}}
更新设备属性
path:/iotx/ilop/updateComponentProduct version:1.0.0 params:更改后的设备list
获取场景列表(已添加到小组件)
path:/living/appwidget/list version:1.0.0 params:@{}
执行场景
path:/scene/fire version:1.0.1 params:@{@"sceneId":sceneId}
更新小组件场景
path:/living/appwidget/create version:1.0.0 params = @{@"sceneIds": @[]}
监听设备属性更新
如果您需要开发控制设备的小组件,通过小组件实现手机对设备的查看和控制。那么您还需要了解App端物模型(属性、事件、服务)相关的知识点。下面以如何用物模型SDK监听设备属性变更事件为例,提供相关的代码示例供您参考。
下面以使用物模型SDK监听设备属性变更事件为例,提供相关的代码示例供您参考。更多内容请参见物模型SDK。
PanelDevice panelDevice = new PanelDevice(iotId);
panelDevice.subAllEvents(new IPanelEventCallback() {
@Override
public void onNotify(String s, String s1, Object o) {
Log.d(TAG, "onNotify: " + s);
Log.d(TAG, "onNotify: " + s1);
Log.d(TAG, "onNotify: " + JSON.toJSONString(o));
// 更新界面
}
}, new IPanelCallback() {
@Override
public void onComplete(boolean b, Object o) {
/* */
}
});
panelDevice.init(this, new IPanelCallback() {
@Override
public void onComplete(boolean b, Object o) {
Log.e(TAG, "panelDevice.init:" + b);
}
});