Android 下 AppWidget 实现时的几个备忘

一个 app 如果要向用户提供 AppWidget(中文多用“小组件”这个名字)的功能的话,跟四大组件类似地,要在 AndroidManifest.xml 中声明。系统/启动器通常都提供了列出所有已安装应用所声明的小组件供用户选择,然后创建到桌面上的入口。在这个列表中出现的每一个小组件,都要在 AndroidManifest.xml 中独立声明,其实质是一个特化的 receiver,其中拥有一个带有名为 android:name 且其值为 android.appwidget.provider 的属性的 meta-data 节点,该节点的另一个名字 android:resource 的值则指向一个 XML 资源,其中详细描述了该小组件的详细规格。

为对应于每个 AppWidget 的 receiver 节点指定一个不同的 android:name 属性值当然是最自然的,不过对于老夫这种本能保守、不愿过多暴露内部实现的程序员来说,想把所有的 AppWidget 都有同一个 provider(也即 receiver 的实现类)来服务也无可厚非。这样做会带来一个问题,就是从启动器的入口创建一个小组件的话,进入首次配置时,要区分用户究竟选择的是哪个小组件。当然,如果原本在 XML 中为每个小组件都指定的是不同的配置 activity,那这个问题也不会出现,凑巧的是,老夫偏偏把配置 activity 也统一指定为同一个了。

假如,provider 不同,而配置 activity 相同,那么在配置 activity 中至少还可以根据 provider 的名字来进行区别,

但是如果 provider 也相同,那就要另辟蹊径了。最直接的想法肯定是在代码中去查看有无 android:resource 的踪迹,对 AppWidgetProviderInfo 类进行考察后,并未发现其中有可供辨识的信息。既然此路不通,又把注意力转到了 receiver 元素本身上,看是否可以利用其某个现成的属性,向其中夹带一些私活。最终选择了 android:label 这个属性,它在 AppWidgetProviderInfo 类中有直接对应的 label 成员。经过测试验证,目的是可以达到的,但有一个副作用,就是这个 label 是会在启动器向用户展示 AppWidget 信息时可见的,这就不适合用作某种内部用途的信息构建了。

经过一番探索,发现 receiver 中是可以放置自定义的 meta-data 元素的,形如 <meta-data android:name="Your Key" android:value="Your Value" /> 即可。经实际测试后验证可行,相关代码如下。

这样一来,就又想到,一开始的 resource 不就是个 meta-data 嘛,何必绕此一圈呢……,不过且慢,似乎当 android:name 为 android.appwidget.provider 时,对应的表示其值的另一属性通常写作 android:resource 而不是 android:value,那这时调用 metaData.getString("android.appwidget.provider") 会发生什么呢?ChatGPT 信誓旦旦说,它会把 android:resource 的值返回,系统框架会跟 android:value 似的一样处理。老夫就姑且信了它罢!

 

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注