Android 中桌面 Widget 的几个相关技术点

widget 是 Android 跟 iOS 很长一段时间以来的一个比较重大的区别,因为后者一度是不支持的。由于失去了竞争,所以也就导致 Android 对 Widget 的支持几乎一直是属于烂泥一滩的状态。要想做出一个非常实用且好看的 Widget,那是非常耗费心神的。

在配置文件中,widget 是无法精确布局的,基本上都是盲人摸象,尽管你可以写最小或者最大允许的缩放 dp 值这些,但无法控制最后 launcher 到底给你分配多大的空间。而且,在度量空间时,除却最常用的 dp,在不少地方需要以 cell 的角度,也即启动器图标网格数来看待问题。与此同时,你既无法得知启动器当前布局的网格规划,也无法得知自身最后到底占据了几个网格。从 Android 12 开始,Google 在配置中又增加了一些相关的配置属性,聊胜于无,这大概是受到了来自 iOS 的冲击后的一个激灵。

用户创建的每一个 widget,都会由系统分配一个 widget ID,app 使用此 ID 来标识对应的 widget,并与其相关数据进行关联。widget 的创建,传统方式一直是从桌面起手,拖放一个 Widget 的预览到桌面上之后,要么当即打开一个界面(配置中的 SettingsActivity)对其进行各种选项的调整,要么就是直接开始第一次的更新(接收到 onUpdate 回调)。如果是前者 widget ID 会传给 Activity,如果是后者,则会传入到 onUpdate 中。但是,onUpdate 既不是某个 ID 的 widget 分别独占的回调,也不是一个仅被调用一次的回调,因此,要从中区分出哪一个 ID 才是刚刚被创建成功的,就需要自行把参数中收到的 ID 与记在记录中既往 ID 集进行比对,只有发现它是“新面孔”的话,那才是了。

后来系统对 Widget 的创建进行了增强,app 可以调用 API 请求系统创建一个 widget。在这种流程下,往往与此 widget 相关的配置都已经在之前的步骤中准备完毕,只差最后的创建步骤。你固然可以像上面一样在 onUpdate 中将最后创建出的 widget ID 挑拣出来,从而完成数据的关联,但是这毫无优雅可言,更何况理论上还会存在多次创建请求的排队,与回调之间的顺序吻合问题。正确的解决方案是使用成功后的回调 Intent,也即 requestPinAppWidget 的 PendingIntent 参数。在 Ietent 参数中,app 最好定义自己的 action,以便从 onReceive 回调中第一时间将创建完成的事件分辨出来。另外,要使回调 Intent 可以被修改,否则 widget ID 就无法被附加进去。

 

发表回复

您的电子邮箱地址不会被公开。