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

举报
bug菌 发表于 2025/12/25 17:07:15 2025/12/25
【摘要】 🏆本文收录于「滚雪球学SpringBoot」专栏(全网一个名),手把手带你零基础入门Spring Boot,从入门到就业,助你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!环境说明:Windows 10 + IntelliJ IDEA 2021.3.2 + Jdk 1.8 🧩 摘要说到原子化服务与卡片(Service Widget),我真会...

🏆本文收录于「滚雪球学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?):系统通知你更新(定时/定点/请求刷新等),你拉新数据再 updateForm
  • onFormEvent(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 生命周期 + 动态更新:一张“行为路径图”(记住就能少走弯路🧭)

你可以把卡片的“生命线”想成这样:

  1. 用户添加卡片 → 系统调 onAddForm(你给初始数据)
  2. 系统到点/触发刷新 → 调 onUpdateForm(你拉数据 + updateForm)
  3. 用户点卡片按钮 → 卡片发 postCardAction(message/router/…) → 提供方处理交互
  4. 用户移除卡片 → 调 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-

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。