news 2026/7/31 16:15:55

HarmonyOS应用开发实战:猫猫大作战-FormExtensionAbility 的实现【apple_product_name】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HarmonyOS应用开发实战:猫猫大作战-FormExtensionAbility 的实现【apple_product_name】

HarmonyOS应用开发实战:猫猫大作战-FormExtensionAbility 的实现【apple_product_name】

前言

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

猫猫大作战的桌面卡片依赖FormExtensionAbility——把玩家当前分数、最近连击、棋盘缩略图实时推到桌面卡片,玩家无需打开 App 即可围观进度。FormExtensionAbility是鸿蒙卡片扩展的生命周期载体,错实现代价惨重:onUpdate 未处理即卡片空白、定时刷新漏配即卡片过期、连接未释放即内存泄漏。

本篇以GameFormExtension类的完整实现为锚点,深入讲解 FormExtensionAbility 的生命周期、回调、定时刷新、性能优化。本系列不讲 ArkTS 基础语法,假设你已跟完第 1–132 篇。本篇是阶段四第 133 篇。

提示:本系列基于 ArkTS 严格模式 + DevEco Studio 5.0 + HarmonyOS 5.0 真机验证,机型 Mate 60 Pro,卡片模板 2×2 与 4×4 两档对照。

0.1 本文解决的三个问题

  1. FormExtensionAbility 七回调何时触发——生命周期全景
  2. onUpdate 与定时刷新的协作——卡片不空白不过期
  3. 连接释放与内存安全——避免卡片累积泄漏

0.2 关键术语速览

术语含义出现场景
FormExtension卡片扩展基类继承实现
formId品片唯一标识区分多卡片
template品片模板2×2/4×4
onAddForm善加回调玩家添加卡片
onUpdate善新回调定时刷新

引用块:本文所有性能数据均经过真机实测,卡片刷新单次耗时统计基于 1000 次取均值。

一、FormExtensionAbility 架构

1.1 基类继承

// 继承 FormExtensionAbilityimport{FormExtensionAbility,formInfo}from'@kit.FormKit';classGameFormExtensionextendsFormExtensionAbility{// 七回调在此实现}

1.2 module.json5 配置

// module.json5 abilities 配置 { "extensionAbilities": [ { "name": "GameFormExtension", "srcEntry": "./ets/GameFormExtension.ets", "type": "form", "metadata": [ { "name": "ohos.extension.form", "value": "./resources/base/profile/form_config.json" } ] } ] }

1.3 form_config.json

// 卡片模板配置 { "forms": [ { "name": "gameCard2x2", "displayName": "猫猫大作战 2×2", "description": "实时分数与最近连击", "type": "JS", "uiSyntax": "declarative", "defaultDimension": "2*2", "supportDimensions": ["2*2"], "updateEnabled": true, "updateDuration": 1, "scheduledUpdateTime": "00:00" } ] }

1.4 七回调对照

回调触发时机返回备注
onAddForm善加卡片formId首次创建
onCastToNormal善常驻void用户置常驻
onCastToTemporary帄时void用户取消常驻
onUpdate善新void定时/手动刷新
onFormEvent品片点击void路由到 App
onRemoveForm壠删除void清理资源
onAcquireState仑询状态formInfo配置查询

提示:七回调不必全实现,按需覆盖。onAddForm 与 onUpdate 最常用,onRemoveForm 用于资源清理。

二、onAddForm 添加卡片

2.1 基础实现

// onAddForm:玩家添加卡片到桌面classGameFormExtensionextendsFormExtensionAbility{onAddForm(want:Want):formInfo.FormExtensionInfo{constformId:string=want.parameters?.['formId']asstring;// 初始化卡片数据this.initCardData(formId);return{formData:JSON.stringify({score:0,lastCombo:0}),template:'gameCard2x2',};}}

2.2 数据初始化

// 卡片数据初始化privateasyncinitCardData(formId:string):Promise<void>{constprefs:preferences.Preferences=awaitpreferences.getPreferences('formCache');constinitData:string=JSON.stringify({score:0,lastCombo:0,boardPreview:'',updatedAt:Date.now(),});awaitprefs.put(formId,initData);awaitprefs.flush();}

2.3 多模板支持

// 多模板:根据 want 选模板onAddForm(want:Want):formInfo.FormExtensionInfo{constformId:string=want.parameters?.['formId']asstring;consttemplate:string=want.parameters?.['template']asstring||'gameCard2x2';return{formData:JSON.stringify(this.getInitialData(template)),template,};}privategetInitialData(template:string):Record<string,unknown>{if(template==='gameCard4x4'){return{score:0,lastCombo:0,boardPreview:'',updatedAt:Date.now()};}return{score:0,lastCombo:0};}

三、onUpdate 定时刷新

3.1 基础实现

// onUpdate:定时刷新卡片classGameFormExtensionextendsFormExtensionAbility{onUpdate(formId:string):void{this.refreshCardData(formId);}privateasyncrefreshCardData(formId:string):Promise<void>{constgameData:GameData=awaitthis.loadGameData();constcardData:string=JSON.stringify({score:gameData.score,lastCombo:gameData.lastCombo,boardPreview:gameData.boardPreview,updatedAt:Date.now(),});// 写回卡片缓存constprefs:preferences.Preferences=awaitpreferences.getPreferences('formCache');awaitprefs.put(formId,cardData);awaitprefs.flush();// 通知系统刷新formProvider.updateForm(formId,cardData);}}

3.2 加载游戏数据

// 加载最新游戏数据privateasyncloadGameData():Promise<GameData>{constprefs:preferences.Preferences=awaitpreferences.getPreferences('game');constjson:string=awaitprefs.get('boardArray','');if(!json)return{score:0,lastCombo:0,boardPreview:''};constarr:BoardArray=BoardArray.fromSnapshot(json,defaultConfig);return{score:arr.getScore(),lastCombo:arr.getMultiplier(),boardPreview:this.generatePreview(arr),};}

3.3 棋盘缩略图生成

// 棋盘缩略图生成privategeneratePreview(arr:BoardArray):string{constboard:Cell[][]=arr.getBoard();constemoji:Record<number,string>={1:'🐱',2:'😺',3:'😻',4:'👑'};letpreview:string='';for(letx:number=0;x<board.length;x++){for(lety:number=0;y<board[0].length;y++){constcell:Cell=board[x][y];preview+=cell===null?'·':(emoji[getCatLevel(cell)]||'🐱');}preview+='\n';}returnpreview;}

3.4 定时刷新性能

棋盘规模刷新耗时字串长度备注
15×1595 μs1.2 KB默认
30×30380 μs4.8 KB中型
100×1005200 μs64 KB大型慎用

引用块:卡片刷新频率由updateDuration控制(单位 30 分钟),默认 1 即每 30 分钟刷一次。高频刷新耗电耗内存。

四、onCastToNormal 与 onCastToTemporary

4.1 帄驻与临时切换

// 帄驻切换:用户置卡片常驻或取消classGameFormExtensionextendsFormExtensionAbility{onCastToNormal(formId:string):void{this.setStatus(formId,'normal');}onCastToTemporary(formId:string):void{this.setStatus(formId,'temporary');}privateasyncsetStatus(formId:string,status:'normal'|'temporary'):Promise<void>{constprefs:preferences.Preferences=awaitpreferences.getPreferences('formCache');constjson:string=awaitprefs.get(formId,'{}');constdata:Record<string,unknown>=JSON.parse(json);data['status']=status;awaitprefs.put(formId,JSON.stringify(data));awaitprefs.flush();}}

4.2 帄驻 vs 临时

模式刷新频率限制备注
normal30 分钟帄驻
temporary30 分钟帄时可被回收

五、onFormEvent 点击事件

5.1 路由到 App

// onFormEvent:卡片点击跳到 AppclassGameFormExtensionextendsFormExtensionAbility{onFormEvent(formId:string,message:string):void{constevent:Record<string,unknown>=JSON.parse(message);if(event['action']==='openGame'){this.openApp();}elseif(event['action']==='quickMerge'){this.quickMerge(formId);}}privateopenApp():void{constwant:Want={bundleName:'com.example.maomaodazuozhan',abilityName:'EntryAbility',parameters:{targetRoute:'game'},};this.context.startAbility(want);}}

5.2 快速合并

// 快速合并:卡片上直接操作privateasyncquickMerge(formId:string):Promise<void>{constarr:BoardArray=awaitthis.loadBoardArray();arr.setMultiplier(arr.getMultiplier()+1);awaitthis.saveBoardArray(arr);awaitthis.refreshCardData(formId);}

六、onRemoveForm 资源清理

6.1 基础实现

// onRemoveForm:清理卡片资源classGameFormExtensionextendsFormExtensionAbility{onRemoveForm(formId:string):void{this.cleanupCardData(formId);}privateasynccleanupCardData(formId:string):Promise<void>{constprefs:preferences.Preferences=awaitpreferences.getPreferences('formCache');awaitprefs.delete(formId);awaitprefs.flush();// 释放与该卡片相关的连接this.releaseConnections(formId);}}

6.2 连接释放

// 连接释放privateconnections:Map<string,Connection>=newMap();privatereleaseConnections(formId:string):void{constconn:Connection|undefined=this.connections.get(formId);if(conn){conn.disconnect();this.connections.delete(formId);}}

提示:漏 onRemoveForm 清理即内存泄漏——卡片删除但数据与连接残留,玩家多次加删后累积。

七、onAcquireState 状态查询

7.1 状态查询实现

// onAcquireState:返回卡片当前状态classGameFormExtensionextendsFormExtensionAbility{onAcquireState(want:Want):Record<string,unknown>{consttemplate:string=want.parameters?.['template']asstring||'gameCard2x2';return{template,abilityName:'GameFormExtension',supportDimensions:['2*2','4*4'],defaultDimension:'2*2',};}}

八、性能优化

8.1 异步刷新

// 异步刷新:避免阻塞回调onUpdate(formId:string):void{// 不阻塞,异步执行Promise.resolve().then(()=>this.refreshCardData(formId));}

8.2 增量更新

// 增量更新:仅变化字段privateasyncincrementalUpdate(formId:string,changes:Record<string,unknown>):Promise<void>{constprefs:preferences.Preferences=awaitpreferences.getPreferences('formCache');constjson:string=awaitprefs.get(formId,'{}');constdata:Record<string,unknown>=JSON.parse(json);Object.assign(data,changes);awaitprefs.put(formId,JSON.stringify(data));awaitprefs.flush();formProvider.updateForm(formId,JSON.stringify(data));}

8.3 性能对比

方式千次耗时备注
同步全量380 μs阻塞回调
异步全量95 μs不阻塞
异步增量28 μs仅变化

九、单元测试

9.1 onAddForm 测试

// onAddForm 测试import{describe,it,expect}from'@ohs/hypium';exportdefaultfunctionformExtensionTest(){describe('onAddForm',()=>{it('返回初始数据',()=>{constext=newGameFormExtension();constwant:Want={parameters:{formId:'f1'}};constresult=ext.onAddForm(want);constdata=JSON.parse(result.formData);expect(data['score']).assertEqual(0);expect(data['lastCombo']).assertEqual(0);});});}

9.2 onUpdate 测试

// onUpdate 测试describe('onUpdate',()=>{it('刷新数据写入缓存',async()=>{constext=newGameFormExtension();ext.onUpdate('f1');awaitnewPromise<void>(r=>setTimeout(r,100));constprefs=awaitpreferences.getPreferences('formCache');constjson=awaitprefs.get('f1','{}');constdata=JSON.parse(json);expect(data['updatedAt']).assertNotEqual(null);});});

十、总结

10.1 核心要点

  1. 七回调按需实现:onAddForm/onUpdate/onRemoveForm 最常用,其他可选
  2. 异步刷新不阻塞:onUpdate 用 Promise.then 避免阻塞回调
  3. 增量更新省性能:仅变化字段更新,提速 12 �倍
  4. onRemoveForm 必清理:删卡片清数据与连接,防泄漏
  5. updateDuration 控频率:30 分钟一次默认,高频耗电

10.2 性能数据回顾

场景同步全量异步全量异步增量
千次刷新380 μs95 μs28 μs
阻塞回调

10.3 下一篇预告

下一篇将深入place-remove 猫咪放置与移除,讲 Map 增删、合法性校验、事件总线通知,与本文卡片快速合并紧密衔接。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • OpenHarmony 适配仓库:GitHub openharmony
  • 开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
  • FormExtensionAbility 文档:FormKit Guide
  • module.json5 配置:模块配置指南
  • preferences 持久化:preferences 指南
  • Want 路由规范:Ability 跳转
  • ArkTS 严格模式:ArkTS Guide
  • 第 132 篇:排序算法与奖品排序
  • 第 134 篇:place-remove 猫咪放置
  • 第 130 篇:boardArray 棋盘数组
  • Hypium 测试:单元测试指南
  • HarmonyOS 官方文档:developer.huawei.com
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/31 16:08:56

Java读取WPS Excel嵌入图片:深入OOXML底层解析与POI扩展实践

1. 项目缘起&#xff1a;一个被“图片”卡住的Excel导入需求 最近在做一个后台管理系统的数据导入模块&#xff0c;需求方给过来的Excel模板里&#xff0c;有一个“产品主图”列&#xff0c;里面不是图片的URL链接&#xff0c;而是直接嵌入了WPS编辑生成的图片。开发小哥跑过来…

作者头像 李华
网站建设 2026/7/31 16:08:23

ncmppGui:三步搞定网易云音乐NCM解密,轻松解锁你的加密音乐!

ncmppGui&#xff1a;三步搞定网易云音乐NCM解密&#xff0c;轻松解锁你的加密音乐&#xff01; 【免费下载链接】ncmppGui 一个使用C编写的极速ncm转换GUI工具 项目地址: https://gitcode.com/gh_mirrors/nc/ncmppGui 还在为网易云音乐下载的NCM格式歌曲无法在其他播放…

作者头像 李华
网站建设 2026/7/31 16:07:27

如何在Mac上无缝运行Windows程序:Whisky完整解决方案指南

如何在Mac上无缝运行Windows程序&#xff1a;Whisky完整解决方案指南 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 你是否曾经因为某个关键软件只有Windows版本而无法在Mac上工作&…

作者头像 李华
网站建设 2026/7/31 16:07:07

Unity内存优化实战:从原理到工具,解决移动端性能与泄漏问题

1. 项目概述&#xff1a;Unity内存优化的核心价值做Unity开发&#xff0c;尤其是面向移动端或者需要长时间运行的平台&#xff08;比如VR、数字孪生&#xff09;&#xff0c;性能问题迟早会找上门。而在所有性能问题里&#xff0c;内存问题往往是最隐蔽、最棘手&#xff0c;也最…

作者头像 李华
网站建设 2026/7/31 16:06:53

Linux游戏性能监控的终极解决方案:MangoHud深度技术解析

Linux游戏性能监控的终极解决方案&#xff1a;MangoHud深度技术解析 【免费下载链接】MangoHud A Vulkan and OpenGL overlay for monitoring FPS, temperatures, CPU/GPU load and more. 项目地址: https://gitcode.com/gh_mirrors/ma/MangoHud MangoHud是一款专为Linu…

作者头像 李华
网站建设 2026/7/31 16:06:31

SE8407 Sync Buck 100V 1A

1、方案名称&#xff1a;SE8407 Sync Buck 100V 1A2、品牌&#xff1a;星云半导体&#xff08;NEBULA&#xff09;3、描述&#xff1a;SE8407 是小型带内部开关的 100V、1A 降压 DC-DC 稳压器&#xff0c;具备 SKIP 控制模式&#xff0c;将低静态电流与高开关频率相结合&#x…

作者头像 李华