AppWidget 浅析

1,034 阅读5分钟

img

1 、AppWidget 简介

  • 桌面插件
  • 服务核心在 AppWidgetService 中,它是系统应用,在 SystemServer 进程中
  • AppWidget 的提供方由应用提供
  • 显示方: 基本运行在 Launcher 中
  • 支持的空间是局限性的,比如不支持 RecyclerView 等
  • RemoteViews 在Android 中的使用场景主要有: 自定义通知栏和桌面小部件

2. AppWidget 提供方

2.1 XML

  • minHeight、minWidth 定义Widget的最小高度和最小宽度(Widget可以通过拉伸来调整尺寸大小)。

  • previewImage 定义添加小部件时显示的图标。

  • initialLayout 定义了小部件使用的布局。

  • updatePeriodMillis 定义小部件自动更新的周期,单位为毫秒。

  • resizeMode 指定了 widget 的调整尺寸的规则。可取的值有: “horizontal”, “vertical”, “none”。“horizontal"意味着widget可以水平拉伸,“vertical”意味着widget可以竖值拉伸,“none”意味着widget不能拉伸;默认值是"none”。

  • widgetCategory 指定了 widget 能显示的地方:能否显示在 home Screen 或 lock screen 或 两者都可以。它的取值包括:“home_screen” 和 “keyguard”。Android 4.2 引入。

2.2 AppWidgetProvider重载方法

  • **onUpdate()**当Widget被添加或者被更新时会调用该方法。上边我们提到通过配置updatePeriodMillis可以定期更新Widget。但是当我们在widget的配置文件中声明了android:configure的时候,添加Widget时则不会调用onUpdate方法。

  • **onAppWidgetOptionsChanged()**这个方法会在添加Widget或者改变Widget的大小时候被调用。在这个方法中我们还可以根据Widget的大小来选择性的显示或隐藏某些控件。

  • **onDeleted(Context, int[])**当控件被删除的时候调用该方法。

  • onEnable(Context) 第一个加入到屏幕上。

  • **onDisabled(Context)**最后一个widget从屏幕移除。

  • onReceive(Context, Intent) 当接收到广播的时候会被调用。

2.3 AppWidgetProvider的使用经验

  • 作为AppWidgetProvider的实现者,一定要实现onUpdate函数,因为这个函数决定widget的显示方式,如果没有这个函数widget根本没办法出现。
  • onUpdate的实现基本上遵循下面的流程:
    • 创建RemoteViews。
    • 调用AppWidgetManager的updateAppWidget去更新widget。

3. AppWidget 显示方

3.1 AppWidgetHost

  • AppWidgetHost 是实际控制widget的地方,大家注意,widget不是一个单独的用户界面程序,他必须寄生在某个程序(activity)中,这样如果程序要支持widget寄生就要实现AppWidgetHost。
  • 它的主要功能有两个:
    • 监听来自AppWidgetService的事件。
    • 另外一个功能就是创建AppWidgetHostView。
  • RemoteViews不是真正的View,只是View的描述,而 AppWidgetHostView才是真正的View。这里先创建AppWidgetHostView,然后通过AppWidgetService查询 appWidgetId对应的RemoteViews,最后把RemoteViews传递给AppWidgetHostView去updateAppWidget。
  • AppWidgetHost和AppWidgetHostView是在框架中定义的两个基类。应用程序可以利用这两个类来实现自己的Host。Launcher是缺省的桌面,它是一个Host的实现者。
  • AppWidgetHostView是真正的View,但它只是一个容器,用来容纳实际的AppWidget的View。这个AppWidget的View是根据RemoteViews的描述来创建。

3.2 Launcher3中对widget的使用理解

  • Launcher3对所有widget的遍历是在AppWidgetManagerCompat及其子类中。
  • 通过AppWidgetManager的getInstalledProvidersForProfile / getInstalledProvidersForPackage(Android版本差异),获取到AppWidgetProviderInfo的集合。
  • LauncherAppWidgetHost负责监听更新更新和创建LauncherAppWidgetHostView。
  • LauncherAppWidgetHostView扩展了AppWidgetHostView,实现了对长按事件的处理。
  • LauncherAppWidgetHost扩展了AppWidgetHost,这里只是重载了onCreateView,创建LauncherAppWidgetHostView的实例。

4. AppWidget服务方

4.1 服务框架

  • AppWidgetService是框架的的核心类,是系统 service之一,它负责widgets的管理工作。加载,删除,定时事件等都需要AppWidgetService的处理。开机自启动的。
  • AppWidgetService存在的目的主要是解开AppWidgetProvider和AppWidgetHost之间的耦合。如果 AppWidgetProvider和AppWidgetHost的关系固定死了,AppWidget就无法在任意进程里显示了。而有了 AppWidgetService,AppWidgetProvider根本不需要知道自己的AppWidget在哪里显示了。
  • AppWidgetManager 负责widget视图的实际更新以及相关管理。

AppWidgetProvider中的onUpdate()参数appWidgetIds为什么是个数组?

个AppWidgetProvider可能被多个地方使用,可能会有几个实例存在,数组就是对应的多个实例的存在场景,可以进行区分更新。但是一般来说,只会有一个。

AppWidget的更新过程可以说的通俗一点吗?

  • Widget更新:提供方把应用信息 + RemoteViews包装好发给发给服务方(这些只是信息结构体,其实并不是View),显示方监听从服务方的回调,在回调中可以拿到这些信息结构体。
  • 理解方式:虽然我们的目的是更新View,但是我们不能用更新View的思路去理解,只能用更新Data的思路去理解。
  • 马夫与马:更新频繁当然不好,因为虽然在应用提供方不涉及View的频繁加载,但是在显示方(要通过数据结构生成View),这就是系统原生为什么把AppWidget 的被动刷新频率下限设定为半小时。就怕马夫(提供方)赶马(显示方),马累死了。

RemoteViews的理解

  • RemoteViews并不是一个真正的View,它没有实现View的接口,而只是一个用于描述View的实体。比如:创建View需要的资源ID和各个控件的事件响应方法。RemoteViews会通过进程间通信机制传递给AppWidgetHost。
  • 现在我们可以看出,Android中的AppWidget与google widget和中移动的widget并不是一个概念,这里的AppWidget只是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法。View在另 外一个进程里显示,但事件的处理方法还是在原来的进程里。

全流程处理时序简单说明。

  • AppWidgetService启动:SystemServer服务,开机启动。
  • AppWidgetProviderInfo获取:AppWidgetService通过PMS针对注册了ACTION_APPWIDGET_UPDATE("android.appwidget.action.APPWIDGET_UPDATE")的静态广播进行扫描查询。
  • meta-data解析:查询到的就是AppWidget,然后从其配置的meta-data中的"appwidget-provider"对应的xml文件开始解析生成AppWidgetProviderInfo结构体。
  • Launcher3获取Widget信息:Launcher通过AppWidgetManager向AppWidgetService按需拿到所有的AppWidget信息,可以进行展示。
  • Launcher3显示Widget信息:Launcher创建AppWidgetHost,通过上面拿到的Widget信息生成对应的AppWidgetHostView进行展示。
  • Launcher3更新Widget信息:AppWidgetHost创建监听AppWidgetService的更新,进行接收回调显示更新。
  • AppWidget被动刷新:AppWidgetService会根据AppWidgetProviderInfo的配置维持一个30分钟下限的更新时钟,来给AppWidgetProvider来发送更新通知。
  • AppWidget主动刷新:应用侧可以拿到AppWidgetManager来进行主动刷新。