原子化服务与卡片开发:你做的卡片,真的“服务”了吗?

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8
🧩 摘要
说到原子化服务与卡片(Service Widget),我真会忍不住来一句:你做卡片是为了“摆着好看”,还是为了让用户“看一眼就想点”呀😏?
别小看这块——卡片做得好,用户用起来像走捷径🚀;做得一般嘛……就像把海报贴桌面上,漂亮但没用🥲。
🪪 16.1 Service Widget(卡片)到底是什么?(一句话讲明白🤌)
Form Kit(卡片开发服务)允许你把应用/元服务里用户最关心的信息和最常用的操作“抽出来”,放到桌面、锁屏等系统宿主上,让用户不用进应用也能看、能点、能办事✅。而且应用和元服务都支持开发卡片,设备覆盖也挺广(手机/平板/PC/2in1/智慧屏/手表等)
卡片场景里有三位“角色演员”🎭:
- 卡片使用方:比如桌面(宿主,负责展示和交互)
- 卡片提供方:你的应用/元服务(负责 UI、数据、点击处理)
- 卡片管理服务:系统的桥梁(负责调度、添加删除、刷新通知)
🔄 16.2 动态更新:别让卡片“活着”,但信息“死了”😵💫
先给你一个工程里最实用的刷新心智模型(我自己就靠它少踩坑):
✅ 刷新分两大类:主动刷新 & 被动刷新
官方把 ArkTS 卡片页面刷新分为:主动刷新(提供方或使用方主动触发)和被动刷新(定时/定点)
而不管哪种刷新,核心都是:
提供方最终都要把“新数据”推给卡片(updateForm)
⚠️ 一个很关键但很多人会忽略的点(我当年就栽过😭)
卡片进程与提供方进程是相互独立的,数据共享不能靠 getContext,需要通过 LocalStorageProp 这类方式接收,而且数据会按 string 处理
——翻译成人话:别指望卡片里“顺手拿个上下文”干大事,会翻车🙂。
🧱 16.3 卡片提供方生命周期:你得知道系统啥时候来敲门🚪👀
卡片提供方在 Stage 模型下通常用 FormExtensionAbility 来接收系统调度,它负责卡片创建、销毁、刷新、事件等生命周期回调
常用回调你至少要认识这些(不然 debug 像蒙眼拆炸弹💣):
onAddForm(want):创建卡片/预览时回调,返回初始展示数据onUpdateForm(formId, wantParams?):系统通知你更新(定时/定点/请求刷新等),你拉新数据再 updateFormonFormEvent(formId, message):卡片里触发 message 事件后回调(点击按钮、交互刷新常用)onRemoveForm(formId):卡片被移除/销毁时回调([华为开发者][3])
还有两个“细思极恐”的官方提醒(我建议你贴到显示器边上📌):
- FormExtensionAbility 创建后 10 秒内无操作会被清理
- 有些模块不支持在 FormExtensionAbility 里引用,不然可能异常退出(比如某些多媒体、后台任务相关模块等)
所以别在这里搞“长耗时任务”,要么快速结束,要么拉起主应用处理,处理完再 updateForm 刷新——这才是成熟做法😌。
🧪 16.4 代码实战:从“创建数据”到“刷新数据”一条龙🐉
下面给你一个最小可用闭环:
onAddForm给初始数据onUpdateForm拉取新数据并formProvider.updateForm刷新- 顺手安排一个“下次刷新时间”(至少 5 分钟)
setFormNextRefreshTime
✅ 1)提供方:EntryFormAbility(生命周期处理)
// EntryFormAbility.ets
import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'
import formBindingData from '@ohos.app.form.formBindingData'
import formProvider from '@ohos.app.form.formProvider'
function buildPayload(title: string, value: string) {
// 卡片数据最终会以字符串形式在卡片侧接收(工程里建议统一 JSON stringify):contentReference[oaicite:15]{index=15}
return formBindingData.createFormBindingData({
title,
value,
ts: `${Date.now()}`
})
}
export default class EntryFormAbility extends FormExtensionAbility {
onAddForm(want) {
// 创建/预览时返回初始数据:contentReference[oaicite:16]{index=16}
return buildPayload('📌 今日状态', '刚创建,先别急😄')
}
async onUpdateForm(formId: string) {
// 系统通知更新时回调,你负责拿最新数据然后 updateForm:contentReference[oaicite:17]{index=17}
const now = new Date()
const payload = buildPayload('⏱️ 更新时间', now.toLocaleTimeString())
await formProvider.updateForm(formId, payload) // 更新卡片:contentReference[oaicite:18]{index=18}
// 设定“下次刷新”(>=5分钟),别太勤快,不然像蚊子一样惹人烦🦟:contentReference[oaicite:19]{index=19}
await formProvider.setFormNextRefreshTime(formId, 5)
}
onRemoveForm(formId: string) {
// 卡片销毁清理:contentReference[oaicite:20]{index=20}
console.info(`[Widget] removed: ${formId}`)
}
onFormEvent(formId: string, message: string) {
// 卡片侧 message 交互会进这里:contentReference[oaicite:21]{index=21}
console.info(`[Widget] event: ${formId}, msg=${message}`)
}
}
🎮 16.5 交互设计:卡片别只会“展示”,得能“办事”😏🧠
卡片里和提供方应用交互,官方提供了 postCardAction,支持三种类型:
router:跳转到提供方应用的指定页面message:发消息给 FormExtensionAbility(常用于“点一下就刷新/切换状态”)call:更偏能力调用(这里先不展开,避免你一口吃成胖子😅)
✅ 1)卡片内:点击按钮发 message(请求刷新/切换)
// WidgetCard.ets(示意:卡片UI)
import { postCardAction } from '@ohos.postCardAction'
@Entry
@Component
struct WidgetCard {
@LocalStorageProp('title') title: string = ''
@LocalStorageProp('value') value: string = ''
build() {
Column({ space: 8 }) {
Text(this.title || '🧩 Service Widget').fontSize(18).fontWeight(FontWeight.Bold)
Text(this.value || '还没数据,别慌😄').fontSize(14)
Row({ space: 10 }) {
Button('🔄 刷新一下')
.onClick(() => {
// message:触发提供方 onFormEvent(formId, message):contentReference[oaicite:23]{index=23}
postCardAction(this, {
action: 'message',
params: { cmd: 'refresh', ts: `${Date.now()}` }
})
})
Button('➡️ 去应用看看')
.onClick(() => {
// router:跳转到提供方应用页面:contentReference[oaicite:24]{index=24}
postCardAction(this, {
action: 'router',
// 具体路由能力与配置见 router 事件指导
uri: 'example://uri.ohos.com/link_page',
params: { from: 'widget' }
})
})
}
}
.padding(12)
}
}
交互设计的“人性化小口诀”我送你一句:
卡片上只放“高频、低成本、低风险”的操作。
比如“签到/刷新/一键开关/快捷进入详情”,别把“支付/删除/重置系统”这种高风险按钮塞卡片里……用户一哆嗦你就白干了🥲
⏳ 16.6 被动刷新配置:updateDuration / scheduledUpdateTime 别乱填😅
如果你想让卡片自己定时更新,通常会在卡片配置里声明定时刷新(updateDuration)或定点刷新(scheduledUpdateTime)。并且有个新规则:当 updateEnabled=true 时,这俩不能都空;二选一即可,而且两者同时配时定时刷新优先生效
我个人建议:
- 信息变动频繁(但不要求秒级):用 updateDuration
- 每天固定时刻(比如早晨/下班前):用 scheduledUpdateTime
别贪心同时搞一堆,不然你自己都解释不清刷新逻辑😵💫
🧬 16.7 生命周期 + 动态更新:一张“行为路径图”(记住就能少走弯路🧭)
你可以把卡片的“生命线”想成这样:
- 用户添加卡片 → 系统调
onAddForm(你给初始数据) - 系统到点/触发刷新 → 调
onUpdateForm(你拉数据 + updateForm) - 用户点卡片按钮 → 卡片发 postCardAction(message/router/…) → 提供方处理交互
- 用户移除卡片 → 调
onRemoveForm(你清理记录)
关键是第 2 步:刷新不是“卡片自己变”,而是提供方把新数据推过去
这就像你给朋友更新朋友圈:不是他盯着屏幕自己刷新,是你发了新动态他才看到😂。
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学SpringBoot」专栏(全网一个名),bug菌郑重承诺,凡是学习此专栏的同学,均能获取到所需的知识和技能,全网最快速入门SpringBoot,就像滚雪球一样,越滚越大, 无边无际,指数级提升。
最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。
同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。
✨️ Who am I?
我是bug菌(全网一个名),CSDN | 掘金 | InfoQ | 51CTO | 华为云 | 阿里云 | 腾讯云 等社区博客专家,C站博客之星Top30,华为云多年度十佳博主/价值贡献奖,掘金多年度人气作者Top40,掘金等各大社区平台签约作者,51CTO年度博主Top12,掘金/InfoQ/51CTO等社区优质创作者;全网粉丝合计 30w+;更多精彩福利点击这里;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试真题、4000G PDF电子书籍、简历模板等海量资料,你想要的我都有,关键是你不来拿。

-End-
- 点赞
- 收藏
- 关注作者
评论(0)