Android AppWidget

Read The Fucking Source Code

引言
  • Android AppWidget相对偏冷门。
  • 开门见山一张图,复杂问题庖解牛。


    Android AppWidget 整体架构图

1. AppWidget简介

  • Android widget 也称为桌面插件,其是android系统应用开发层面的一部分,但是又有特殊用途,而且会成为整个android系统的亮点。Android中的AppWidget与google widget和中移动的widget并不是一个概念,这里的AppWidget只是把一个进程的控件嵌入到别外一个进程的窗口里的一种方法。
  • AppWidget的服务核心在AppWidgetService中,它是系统应用,在SystemServer进程中。
  • AppWidget的提供方由应用提供(对大部分应用开发者来说,了解操作这一块就够了)。
  • AppWidget的显示方,基本上运行在Launcher中。
  • AppWidget支持的控件是由局限性的,比如不支持RecyclerView等。
  • RemoteViews 在Android中的使用场景主要有:自定义通知栏和桌面小部件。

2. AppWidget提供方

2.1 XML <appwidget-provider>

  • 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的实例。

3.3 Launcher3核心代码

Launcher3核心代码-按需遍历Widget集合
Launcher3核心代码-Widget的监听生成

4. AppWidget服务方

4.1 服务框架

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

5. 我对整体AppWidget的理解

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来进行主动刷新。

6. 附录(Framework层的代码路径及结构)

提供方-显示方-代码码路径
服务方-代码路径

小编的博客系列

Android Framework 全家桶

优秀博客推荐

Android官网
Android列表小部件(Widget)开发详解
Android UI组件----AppWidget控件入门详解
Android之AppWidget(桌面小部件)开发浅析
Android之Widget
Android中Launcher对于AppWidget处理的分析:AppWidgetHost角色
Android widget使用心得
Android Widget小组件开发(一)
android开发之widget控件突然停止更新的原因

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容