Android API指南之应用程序窗口小部件主机

本文与公众号三七文档库同步。

本文由三七原创翻译,转载前务必联系三七。

大多数Android设备上提供的Android主屏幕允许用户嵌入应用程序窗口小部件以快速访问内容。如果您正在构建一个代替主页或类似的应用,您也可以通过实现AppWidgetHost来允许用户嵌入应用程序窗口小部件。这不是大多数应用程序需要做的事情,但是如果您要创建自己的主机,了解主机默认同意的规则是约定义务重要的。

本文档的重点包含实现一个自定义的AppWidgetHost。有关如何实现一个AppWidgetHost,请参阅Android主屏幕“启动器”的源码。

以下是自定义AppWidgetHost所涉及的关键类和概念的概述:

  • 应用程序窗口小部件主机AppWidgetHost为应用程序提供了与应用程序窗口小部件服务的交互,例如主屏幕,想要将应用程序窗口小部件嵌入到其UI中。一个AppWidgetHost必须有一个ID,它在主机本身的包中是唯一的。该ID在主机所有的使用过程中保持不变。该ID通常是您在应用程序中分配的硬编码值。
  • 应用程序窗口小部件ID— 每个应用程序窗口小部件实例在绑定时都被分配一个唯一的ID(请参阅bindAppWidgetIdIfAllowed(),更详细的讨论在绑定应用程序窗口小部件中)。唯一ID是由主机使用allocateAppWidgetId()获取的。该ID在窗口小部件的整个生命周期内都是持久的,也就是说知道从主机中删除。任何主机特定的状态(如窗口小部件的大小和位置)都应由主机包持久保存,并与应用程序窗口小部件ID相关联。
  • 应用程序窗口小部件主机视图AppWidgetHostView可以被认为是窗口小部件需要显示时所包裹的帧。每次窗口小部件被主机充满时都会被分配给一个AppWidgetHostView
  • 可选的BundleAppWidgetHost使用可选的bundle和AppWidgetProvider传递关于窗口小部件如何显示(例如,大小范围,以及窗口小部件是在锁屏还是在主屏幕上)的信息。该信息允许AppWidgetProvider根据显示的方式和位置来定制窗口小部件的内容和外观。您可以使用updateAppWidgetOptions()updateAppWidgetSize()来修改一个应用程序窗口小部件的bundle。这两个方法都会触发一个回调给AppWidgetProvider

绑定应用程序窗口小部件

当用户将一个应用程序窗口小部件添加到主机时,会产生一个称为绑定的过程。
绑定是指将特定的应用程序窗口小部件ID关联到特定的主机和特定的AppWidgetProvider。有不同的方式来实现这个过程,取决于您的应用程序运行在哪个Android版本。

在Android 4.0及更低版本上绑定应用程序窗口小部件

在运行Android 4.0及更低版本的设备上,用户通过允许用户选择窗口小部件的系统activity添加应用程序窗口小部件。这样隐式做了一个权限检查 - 也就是说,通过添加应用程序窗口小部件,用户隐式授予您的应用程序添加应用程序窗口小部件到主机的权限。下面是一个例子,说明了这种方法,摘录自原来的启动器。在这个片段中,一个事件处理器调用携带请求码为REQUEST_PICK_APPWIDGETstartActivityForResult()来响应用户操作:

private static final int REQUEST_CREATE_APPWIDGET = 5;
private static final int REQUEST_PICK_APPWIDGET = 9;
...
public void onClick(DialogInterface dialog, int which) {
    switch (which) {
    ...
        case AddAdapter.ITEM_APPWIDGET: {
            ...
            int appWidgetId =
                    Launcher.this.mAppWidgetHost.allocateAppWidgetId();
            Intent pickIntent =
                    new Intent(AppWidgetManager.ACTION_APPWIDGET_PICK);
            pickIntent.putExtra
                    (AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
            ...
            startActivityForResult(pickIntent, REQUEST_PICK_APPWIDGET);
            break;
    }
    ...
}

当系统activity结束时,它会将带用户的选择的应用程序窗口小部件的结果返回给您的activity。在以下示例中,activity通过调用addAppWidget()添加应用程序窗口小部件来响应。

public final class Launcher extends Activity
        implements View.OnClickListener, OnLongClickListener {
    ...
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        mWaitingForResult = false;

        if (resultCode == RESULT_OK && mAddItemCellInfo != null) {
            switch (requestCode) {
                ...
                case REQUEST_PICK_APPWIDGET:
                    addAppWidget(data);
                    break;
                case REQUEST_CREATE_APPWIDGET:
                    completeAddAppWidget(data, mAddItemCellInfo, !mDesktopLocked);
                    break;
                }
        }
        ...
    }
}

addAppWidget()方法检查应用程序窗口小部件是否需要在添加之前配置:

void addAppWidget(Intent data) {
    int appWidgetId = data.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, -1);

    String customWidget = data.getStringExtra(EXTRA_CUSTOM_WIDGET);
    AppWidgetProviderInfo appWidget =
            mAppWidgetManager.getAppWidgetInfo(appWidgetId);

    if (appWidget.configure != null) {
        // Launch over to configure widget, if needed.
        Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_CONFIGURE);
        intent.setComponent(appWidget.configure);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        startActivityForResult(intent, REQUEST_CREATE_APPWIDGET);
    } else {
        // Otherwise, finish adding the widget.
    }
}

有关配置的更多讨论,请参阅创建一个应用程序窗口小部件配置Activity

一旦应用程序窗口小部件准备就绪,下一步就是做将它添加到工作区的实际工作。原来的启动器使用称为completeAddAppWidget()来做到这一点。

在Android 4.1及更高版本绑定应用程序窗口小部件

Android 4.1增加了更精简的绑定过程的API。这些API也让host可以为绑定提供自定义的UI。要使用这个改进的过程,您的应用程序必须在清单文件中声明BIND_APPWIDGET权限:

<uses-permission android:name="android.permission.BIND_APPWIDGET" />

但这只是第一步。在运行时,用户必须明确授予您的应用程序权限,以允许它将应用程序窗口小部件添加到主机。要验证您的应用程序是否有权限添加窗口小部件,请使用bindAppWidgetIdIfAllowed()方法。如果bindAppWidgetIdIfAllowed()返回false,您的应用程序必须显示一个对话框提示用户授予权限(“允许”或“始终允许”,以覆盖所有以后添加的应用程序窗口小部件)。这个片段给出了一个如何显示对话框的例子:

Intent intent = new Intent(AppWidgetManager.ACTION_APPWIDGET_BIND);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_PROVIDER, info.componentName);
// This is the options bundle discussed above
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_OPTIONS, options);
startActivityForResult(intent, REQUEST_BIND_APPWIDGET);

主机还必须检查用户是否添加了需要配置的应用程序窗口小部件。有关此主题的更多讨论,请参阅创建一个应用程序窗口小部件配置Activity

主机的职责

您的目标版本是什么?

您在实现主机时使用的方法应取决于您的目标Android版本。本节中介绍的许多功能都是在3.0或更高版本中引入的。例如:

  • Android 3.0(API Level 11)引入了窗口小部件的自动更新行为。
  • Android 3.1(API Level 12)引入了调整窗口小部件大小的功能。
  • Android 4.0(API Level 15)引入了填充策略的变化,将主机职责放在管理填充上。
  • Android 4.1(API Level 16)添加了一个API,允许窗口小部件提供者获取有关装载的窗口小部件实例所处环境的更多详细信息。
  • Android 4.2(API Level 17)引入了选项bundle和bindAppWidgetIdIfAllowed()方法。它还介绍了锁屏小部件。

如果您定位的是早期的设备,请参阅原来的启动器

窗口小部件开发人员可以使用AppWidgetProviderInfo元数据为小部件指定一些配置设置。这些配置选项(在下面有更详细的讨论)可以由主机从与窗口小部件提供者相关联的AppWidgetProviderInfo对象中检索。

不管您的目标Android版本是什么,所有的主机都有以下的职责:

  • 添加小部件时,必须按照上面所述分配窗口小部件ID。您还必须确保从主机中删除小部件时,调用deleteAppWidgetId()解除分配窗口小部件ID。
  • 添加小部件时,请确保在其配置活动存在的情况下启动配置activity,如从配置Activity中更新应用程序窗口小部件所述。这是许多应用程序窗口小部件能正确显示的必要步骤。
  • 没一个应用程序窗口小部件以dp为单位指定了最小宽度和高度,如AppWidgetProviderInfo元数据(使用android:minWidthandroid:minHeight)中定义的那样。确保这个窗口小部件的布局至少有这么多dp。例如,许多主机将网格中的图标和小部件对齐。在这种情况下,主机应默认使用满足minWidthminHeight约束的最小数量的格子来添加应用程序窗口小部件。

除了上面累出的要求之外,特定平台版本还引入了在主机上增加新职责的功能。这些在下面的章节中描述。

Android 3.0

Android 3.0(API Level 11)引入了为窗口小部件指定autoAdvanceViewId()的功能。这个视图ID应该指向一个Advanceable实例,比如StackViewAdapterViewFlipper。这表示主机应该在主机认为合适的时间间隔内在这个视图上调用advance()(需要考虑更新窗口小部件是否有意义 - 例如,如果它在另一个页面,或者如果屏幕被关闭,主机可能不希望更新窗口小部件)。

Android 3.1

Android 3.1(API Level 12)引入了调整窗口小部件大小的功能。窗口小部件可以使用AppWidgetProviderInfo中的元数据来指定它是否可以调整大小,并指示它是否支持水平和(或)垂直方向的大小调整。在Android 4.0(API级别14)中,窗口小部件还可以指定android:minResizeWidth和(或)android:minResizeHeight

让窗口小部件可以按照指定在水平和(或)垂直方向上调整大小是主机的职责。指定可调整大小的窗口小部件可以任意调整大小,但不能调整小于android:minResizeWidthandroid:minResizeHeight的值。有关示例实现,请参阅启动器中的AppWidgetResizeFrame

Android 4.0

Android 4.0(API Level 15)引入了padding策略的变化,将主机职责放在管理padding上。从4.0开始,应用程序窗口小部件不再包含自己的padding。相反,系统会根据当前屏幕的特征为每个窗口小部件添加padding。这样就可以在网格中更一致地呈现窗口小部件。为了帮助托管应用程序窗口小部件的应用程序,平台提供了getDefaultPaddingForWidget()方法。应用程序可以调用此方法来获取系统定义的padding并在计算要分配给窗口小部件的单元数时进行计算。

Android 4.1

Android 4.1(API Level 16)添加了一个API,允许窗口小部件提供者获取有关窗口小部件实例的托管环境的更多详细信息。具体来说,主机向窗口小部件提供者提示窗口小部件被显示的大小。提供这个尺寸信息是主机的职责。

主机通过updateAppWidgetSize()提供这个信息。大小以dp为单位指定了最小和最大的宽度/高度。指定范围的原因(与固定大小相反)是窗口小部件的宽度和高度可能随着屏幕方向而改变。您不希望主机在屏幕旋转时强制更新所有的小部件,因为这可能会导致严重的系统卡顿。一旦窗口小部件放置好了,和任何时候调整窗口小部件大小,以及任何时候启动器第一次按特定的引导(因为这些值不会在启动时持久保存)填充窗口小部件时,这些值都应该更新。

Android 4.2

Android 4.2(API Level 17)增加了在绑定时指定可选的bundle的功能。这是指定应用程序窗口小部件选项(包括大小)的理想方法,因为它使得AppWidgetProvider可以在第一次更新时立即访问选项数据。这可以通过使用bindAppWidgetIdIfAllowed()方法来实现。有关此主题的更多讨论,请参阅绑定应用程序窗口小部件

Android 4.2还引入了锁屏窗口小部件。当在锁定屏幕上托管窗口小部件时,主机必须在应用程序窗口小部件的可选bundle中指定此信息(AppWidgetProvider可以使用此信息来适当地设置窗口小部件的样式)。要指定一个窗口小部件作为锁屏小部件,请使用updateAppWidgetOptions(),并包含值为WIDGET_CATEGORY_KEYGUARDOPTION_APPWIDGET_HOST_CATEGORY字段。这个选项默认为WIDGET_CATEGORY_HOME_SCREEN,所以没有明确要求设置其为主屏幕主机。

确保您的主机只添加适合您的应用的应用程序窗口小部件,例如,如果您的主机是主屏幕,请确保元数据中的 android:widgetCategory属性包含WIDGET_CATEGORY_HOME_SCREEN标志。同样,对于锁屏,确保该字段包含WIDGET_CATEGORY_KEYGUARD标志。有关此主题的更多讨论,请参阅在锁定屏幕上启用应用程序窗口小部件

英文原文链接:https://developer.android.com/guide/topics/appwidgets/host.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值