卡片不就是放桌面的小组件吗?那为啥它的更新、交互、生命周期总爱给你“整活儿”?

🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8
🤨 前言
你有没有过这种“桌面一放卡片,我就开始掉头发”的瞬间:卡片刚加上去看着挺美,结果一会儿不更新、一会儿点了没反应、再一会儿生命周期回调压根不进……你盯着桌面,桌面也盯着你:“就这?你还想做原子化服务?😏”
来,今天咱不装斯文——把 原子化服务 & Service Widget(服务卡片) 从“能跑”讲到“跑得稳、更新准、交互顺”,顺便把生命周期那点小脾气也治一治 😄
🧭📌 目录(坑我先替你标出来🕳️)
- 😄📝 前言:卡片看着小,脾气一点不小
- 🧩🧠 原子化服务 & 卡片到底是啥:别把它当“缩小版页面”
- 🧱🗂️ 工程结构:一张卡片通常由哪几块拼起来
- 🧬⏳ 生命周期:FormExtensionAbility 到底会回调哪些方法
- 🔄⚡ 动态更新:updateForm / 下次刷新时间 / “别把电量当仇人”
- 🖱️🎮 交互设计:动态卡片 postCardAction vs 静态卡片 FormLink(别用错!)
- 🧪👨💻 实战代码:做个“天气/待办风格”的可更新卡片(能落地那种)
- 🧯🚑 常见翻车急救:点不动、刷不动、回调不进——怎么救
- ✅🎯 总结:卡片写到这个程度,你就能“安心交付”了
😄📝 前言:卡片看着小,脾气一点不小
卡片这玩意儿,最大的误解就是:
“不就是个小 UI 嘛?照页面写不就行了?”
然后你就会被现实教育:
- 卡片进程可能很快被清理,你刚准备联网,它“啪”一下没了 😅(官方就提到:FormExtensionAbility 创建后 10 秒内无操作会被清理)
- 有些模块在 FormExtensionAbility 里直接不让用,用了可能异常退出(比如粒子能力、音频、相机等)
- 更新有专用通道,不是你在卡片里
setState就能“感动系统”刷新的
所以:卡片开发=UI + 数据绑定 + 更新策略 + 交互链路 + 生命周期治理,缺一块都容易翻车。
🧩🧠 原子化服务 & 卡片到底是啥:别把它当“缩小版页面”🫠
在鸿蒙里,Service Widget(服务卡片)是把“信息/动作”前置到桌面或宿主里,让用户少点两步就能完成关键操作。
它的本质更像“被系统托管的 UI 快照 + 受控的交互入口”,而不是一直常驻、随便跑逻辑的页面。
而卡片提供方侧,你核心要掌握的就是 FormExtensionAbility:它负责卡片的创建、刷新、事件回调、销毁等生命周期能力。
🧱🗂️ 工程结构:一张卡片通常由哪几块拼起来 🧩
我用“人话”给你拆一下常见结构(名字可能随模板略有差异,但角色基本一致):
- 🧠 EntryFormAbility.ets:继承
FormExtensionAbility,处理生命周期(创建/更新/事件/销毁) - 🎨 WidgetCard.ets:卡片 UI(ArkTS 声明式 UI)
- 🧾 form_config.json:卡片配置(尺寸、布局、是否静态等)
你可以把它想成:
UI 负责“长相”,Ability 负责“呼吸和心跳”。
🧬⏳ 生命周期:FormExtensionAbility 到底会回调哪些方法 🧠
官方 API 参考里把一堆回调列得很完整,常用重点是这些:
- 🆕
onAddForm(want):创建卡片时回调(返回要展示的数据) - 🔄
onUpdateForm(formId, wantParams?):更新卡片(你拿到新数据后要主动 updateForm) - 📨
onFormEvent(formId, message):卡片触发 message 事件时回调 - 👀
onChangeFormVisibility(newStatus):可见性变化(注意:有些限制/场景才生效) - 🗑️
onRemoveForm(formId):销毁卡片 - 🧪
onAcquireFormState(want):查询卡片状态(可选重写)
还有两个特别“刺耳”的提醒我建议你贴墙上:
- Stage 模型限定:FormExtensionAbility 仅可在 Stage 模型下使用
- 能力限制:某些模块不支持在 FormExtensionAbility 引用,否则可能异常退出
🔄⚡ 动态更新:updateForm / 下次刷新时间 / “别把电量当仇人”🔋
卡片更新不是“你想刷就刷”,你要用专用 API:formProvider.updateForm()。
同时你还能设置下一次刷新时间:formProvider.setFormNextRefreshTime()。
✅ 更新策略我建议分三层(稳得像老干部😄)
- 🕒 轻量定时:用
setFormNextRefreshTime告诉系统下次何时刷新(别太频繁) - 🧷 用户触发:点“刷新”按钮走 message/call 触发更新(精准又省电)
- 🚀 重逻辑走 UIAbility:卡片侧只做轻处理,复杂网络/计算交给 UIAbility(尤其是 call 事件)
🖱️🎮 交互设计:动态卡片 postCardAction vs 静态卡片 FormLink(别用错!)😤
这块最容易“用错工具还不自知”。
官方交互概述写得很清楚:
- 动态卡片:用
postCardAction - 静态卡片:用
FormLink
并且它们都支持router / message / call三类事件。
🧠 三种事件怎么选(我给你一套“少踩坑”的直觉)
-
🧭
router:点卡片跳到应用页面(UIAbility 前台打开) -
📨
message:不打开页面,把消息交给onFormEvent(更适合“轻交互 + 刷新卡片”) -
☎️
call:后台拉起 UIAbility 执行某个方法(适合“拉数据/算东西/再回写卡片”)- 这里有硬要求:call 事件通常需要传
params.method,并且对 UIAbility 启动模式/后台权限有要求(比如单实例、后台运行权限等)
- 这里有硬要求:call 事件通常需要传
🧪👨💻 实战代码:做个“可更新的小卡片”(带交互、带刷新)✨
下面我给你一套最常用的“卡片三件套”:
- 卡片 UI 用
@LocalStorageProp接数据 - Ability 侧用
formBindingData.createFormBindingData()产出数据 - 更新用
formProvider.updateForm()+(可选)setFormNextRefreshTime()
说明:
@LocalStorageProp/@LocalStorageLink从 API 9 开始支持在 ArkTS 卡片里用(元服务从 API 11 开始支持)。
1)🎨 WidgetCard.ets(卡片 UI:显示 + 点击刷新)
// WidgetCard.ets
@Entry
@Component
struct WidgetCard {
// 卡片数据默认会绑定进 LocalStorage(常见做法就是用装饰器直接读)
@LocalStorageProp('title') title: string = '⛅ 今日状态'
@LocalStorageProp('value') value: string = '--'
@LocalStorageProp('updatedAt') updatedAt: string = ''
build() {
Column() {
Text(`🧩 ${this.title}`).fontSize(16).margin({ bottom: 6 })
Text(`📌 ${this.value}`).fontSize(22).margin({ bottom: 6 })
Text(`🕒 ${this.updatedAt || '还没更新呢…😅'}`).fontSize(12).opacity(0.6)
// ✅ 动态卡片:用 postCardAction
Button('🔄 点我刷新(message)')
.margin({ top: 10 })
.onClick(() => {
// 动态卡片事件:message / router / call
postCardAction(this, {
action: 'message',
params: { type: 'refresh' }
})
})
}
.padding(12)
}
}
postCardAction专用于卡片内部与提供方交互,支持 router/message/call,且仅在卡片中可调用。
2)🧠 EntryFormAbility.ets(生命周期 + 更新)
// EntryFormAbility.ets
import { FormExtensionAbility, formBindingData, formProvider } from '@kit.FormKit'
import { Want } from '@kit.AbilityKit'
function nowString(): string {
const d = new Date()
return `${d.toLocaleDateString()} ${d.toLocaleTimeString()}`
}
export default class EntryFormAbility extends FormExtensionAbility {
// ✅ 创建卡片:返回初始要展示的数据
onAddForm(want: Want): formBindingData.FormBindingData {
// want 里通常能拿到 formId、名称、样式等;这些信息建议持久化管理,便于后续更新/删除:contentReference[oaicite:17]{index=17}
const data = {
title: '⛅ 今日状态',
value: '初始化中…',
updatedAt: nowString()
}
return formBindingData.createFormBindingData(data)
}
// ✅ 系统/宿主请求更新
onUpdateForm(formId: string, wantParams?: Record<string, Object>): void {
const data = {
title: '⛅ 今日状态',
value: `更新成功 ✅(param=${JSON.stringify(wantParams ?? {})})`,
updatedAt: nowString()
}
// 关键:拿到新数据后,主动 updateForm
formProvider.updateForm(formId, formBindingData.createFormBindingData(data))
.then(() => {
// 可选:告诉系统“下次多久再刷新”(别太卷,省点电😄)
// formProvider.setFormNextRefreshTime(formId, Date.now() + 30 * 60 * 1000)
})
.catch((e) => {
console.error(`updateForm failed: ${JSON.stringify(e)}`)
})
}
// ✅ 卡片 message 事件:比如用户点了“刷新”
onFormEvent(formId: string, message: string): void {
// message 是事件消息(你可以用 JSON 字符串传)
const data = {
title: '⛅ 今日状态',
value: `来自点击的刷新 🥳(msg=${message})`,
updatedAt: nowString()
}
formProvider.updateForm(formId, formBindingData.createFormBindingData(data))
.catch(e => console.error(`onFormEvent update failed: ${JSON.stringify(e)}`))
}
// ✅ 销毁:清理与该 formId 相关的资源/缓存
onRemoveForm(formId: string): void {
console.info(`🗑️ onRemoveForm: ${formId}`)
}
}
这段能力链路背后对应的官方能力点:
- FormExtensionAbility 提供创建/更新/事件/销毁回调
- formProvider 提供
updateForm、setFormNextRefreshTime等更新能力
3)🧷 静态卡片交互(如果你做的是静态卡片)
静态卡片别用 postCardAction,要用 FormLink,它也支持 router/message/call。
(示意)
FormLink({
action: 'message',
params: { type: 'refresh' }
}) {
Text('🔄 静态卡片刷新').fontSize(14)
}
🧯🚑 常见翻车急救(真的很常见😭)
1)😵 “点刷新没反应”
- 你做的是 静态卡片 却用了
postCardAction→ 换FormLink - message 发了,但
onFormEvent没处理/没 updateForm → 记得formProvider.updateForm()
2)🥶 “更新回调进了,但 UI 不变”
-
卡片 UI 没用
@LocalStorageProp/@LocalStorageLink绑定对应 key- 这类装饰器支持在 ArkTS 卡片里使用(API 9+),元服务(API 11+)
-
你 updateForm 的 key 和 UI 读的 key 对不上(最气人的“拼写错误”🥲)
3)🫥 “生命周期回调偶发不进/执行很短”
- FormExtensionAbility 有存活与能力限制,不要在里面干重活;官方还提示它可能被快速清理,并列出多种不支持模块
✅ 处理:把重逻辑放到 UIAbility(配合 call),FormExtensionAbility 做“拼装数据 + updateForm”就好
✅🎯 总结:卡片写到这个程度,你就能“安心交付”了 😄
你把下面这套“心法”记住,卡片基本就不会再乱搞你:
- 🧬 生命周期靠
FormExtensionAbility管:onAddForm/onUpdateForm/onFormEvent/onRemoveForm(别乱放逻辑) - 🔄 更新靠
formProvider.updateForm:想定时就配setFormNextRefreshTime,但别太频繁 - 🎮 交互分清楚:动态卡片
postCardAction,静态卡片FormLink,都支持 router/message/call,但各有适用场景 - 🧠 数据绑定用
@LocalStorageProp/@LocalStorageLink:卡片里读数据最省心(API 9+ 支持卡片,API 11+ 支持元服务)
🧧福利赠与你🧧
无论你是计算机专业的学生,还是对编程有兴趣的小伙伴,都建议直接毫无顾忌的学习此专栏「滚雪球学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)