App Widget桌面小部件已经被很多APP所使用,在日常的生活中也有很多人在使用,最常见的就是时钟、天气、日历、记事本这样的小工具,但是不少主流APP也提供了一些快捷功能的小部件,例如音乐快捷播放、代办事项、课程表、股票、购物快捷搜索、邮箱邮件等等,桌面小部件是APP部分业务功能的快捷入口,可以有效提升用户的使用体验缩短触达链路。
一、小部件基本组成
1.1 小部件UI布局
和Activity类似,在 XML 资源中为定义初始布局并将其保存在项目的 res/layout/目录中,App Widget 布局基于RemoteViews,它不支持所有类型的容器布局和视图控件。
RemoteViews 可支持的容器和控件如下:
容器
- FrameLayout (帧布局)
- LinearLayout (线性布局)
- RelativeLayout (相对布局)
控件
- AnalogClock (时钟)
- Button (按钮)
- Chronometer (计时器)
- ImageButton (图片按钮)
- ImageView (图片)
- ProgressBar (进度条)
- TextView (文本框)
- ListView (纵向列表)
- GridView (宫格)
- StackView (堆叠)
- ViewFlipper (翻转控件)
- AdapterViewFlipper (翻转控件,但需要Adapter)
并且,不支持继承了上述容器和控件的View,也就是不支持自定义View。
例如:
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/my_widget_background">
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
1.2 AppWidgetProviderInfo 元数据
AppWidgetProviderInfo 用于描述一个 App Widget 的基本属性,如布局文件、布局尺寸、布局可变方向、最小可变布局尺寸、预览图、更新频率、配置Activity。
使用单个<appwidget-provider>
元素在 XML 资源文件中定义 AppWidgetProviderInfo 对象,并将其保存在项目的 res/xml 文件夹中。
例如:
<appwidget-provider
xmlns:android = "http://schemas.android.com/apk/res/android"
android:minWidth = "250dp"
android:minHeight = "110dp"
android:updatePeriodMillis = "86400000"
android:previewImage = "@drawable/preview"
android:initialLayout = "@layout/example_appwidget"
android:configure = "com.example.android.ExampleAppWidgetConfigure"
android:resizeMode = "horizontal|vertical" />
以下是<appwidget-provider>
属性的摘要:
- minWidth和minHeight 属性的值指定默认情况下App Widget 消耗的最小空间量 。默认主屏幕根据具有定义高度和宽度的单元格网格在其窗口中定位应用小部件,如果一个App Widget的最小宽度或高度的值不匹配的单元的尺寸,则会调整到最接近的小区大小。
【注意】为适配不同的屏幕尺寸,小部件的最小尺寸不应大于 4 x 4 单元格。
- minResizeWidth和minResizeHeight属性指定 App Widget 的绝对最小尺寸。这些值应指定应用小部件即将无法辨认或无法使用的大小,使用这些属性允许用户将窗口小部件的大小调整为可能小于由minWidth和minHeight属性定义的默认窗口小部件大小的大小 。
- updatePeriodMillis属性定义了系统更新 App Widget 的频率。不能保证使用此值准确按时进行更新,官方建议尽可能不频繁地进行更新,建议每小时不超过一次以节省电池电量,并且最小值为1800000——即30分钟。
【注意】如果设备在更新时处于睡眠状态,则设备将唤醒以执行更新。如果每小时更新不超过一次,这可能不会对电池寿命造成重大问题。但是,如果需要更频繁地更新或不需要在设备休眠时更新,那么可以根据不会唤醒设备的闹钟执行更新,使用 AppWidgetProvider 接收的 Intent 设置 AlarmManager,将闹钟类型设置为ELAPSED_REALTIME或 RTC,然后设置 updatePeriodMillis为0。
- initialLayout属性指向定义 App Widget 布局的布局资源。
- configure属性定义了在用户添加 App Widget 时启动的配置Activity,以便用户配置 App Widget 属性。
- previewImage属性指定应用小部件在的外观预览图,用户在选择应用小部件时会看到该预览图。如果未提供,用户将看到APP的启动图标。
- resizeMode属性指定可以调整小部件大小的规则。此属性使主屏幕小部件可调整大小——水平、垂直或在两个轴上。用户按住小部件以显示其调整大小手柄,然后拖动水平和/或垂直手柄以更改布局网格上的大小。该resizeMode属性的值 包括“horizontal”、“vertical”和“none”。要将小部件声明为水平和垂直均可调整大小,则使用“horizontal|vertical”。
1.3 AppWidgetProvider 类实现
AppWidgetProvider类是小部件的核心类,继承了BroadcastReceiver,可以处理广播消息。
AppWidgetProvider 仅接收与 App Widget 相关的事件广播,例如 App Widget 何时更新、删除、启用和禁用。
当这些广播事件发生时,AppWidgetProvider 的主要生命周期方法会被调用:
- onUpdate()
此方法会根据配置的 updatePeriodMillis 属性定义的时间间隔进行调用,作用为更新小部件,当用户添加小部件时也会调用此方法,因此它应该执行一些基本的设置。但是,如果你已经声明了一个ConfigureActivity,这个方法在用户添加小部件时不会调用,而是在后续更新时调用。ConfigureActivity负责在配置完成后执行第一次更新。 - onDeleted(Context, int[])
每次从桌面删除小部件时都会调用此方法。 - onEnabled(Context)
只有在桌面上添加对应小部件的第一个实例时会调用此方法。例如,如果用户连续添加了一个小部件两次,只有第一次添加时会调用此方法。 - onDisabled(Context)
当对应小部件的最后一个实例从 App Widget 主机中删除时,会调用此方法,在此方法中应执行资源释放等工作。 - onReceive(Context, Intent)
每次接收到广播和上述每个回调方法之前会调用此方法,主要用于处理点击事件、手动更新等事项。
例如:
public class ExampleAppWidgetProvider extends AppWidgetProvider {
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int N = appWidgetIds.length;
for (int i=0; i<N; i++) {
int appWidgetId = appWidgetIds[i];
// 创建一个打开Activity的Intent
Intent intent = new Intent(context, ExampleActivity