【共创季稿事节】HarmonyOS7 互动卡片开发实践:EntryFormAbility 如何保存和管理卡片实例

【共创季稿事节】HarmonyOS7 互动卡片开发实践:EntryFormAbility 如何保存和管理卡片实例


文章目录

      • 效果图
      • 这篇主要看哪个文件
      • onAddForm 做了什么
      • 第一步:从 want 里拿系统参数
      • 第二步:保存 FormInfo
      • 第三步:音乐卡片特殊处理
      • 返回初始化数据
      • onRemoveForm 也别忘了
      • 小白可以自己写一个最小版
      • 排查清单
      • 写在最后

EntryFormAbility是普通卡片的管家。小白刚接触互动卡片时,最容易忽略它,以为卡片页面写好了就行。

其实不行。桌面上可能同时放了多张音乐卡片、运动卡片、快递卡片。你后面要刷新哪一张?要删除哪一张?要批量更新哪些卡片?这些都要靠EntryFormAbility保存下来的formId

效果图

这一篇不直接讲动画,而是讲这些效果背后的“实例管理”。只有EntryFormAbility记住每一张桌面卡片,后面点击播放、运动、快递、睡眠状态时,才知道该刷新谁。

先把实例保存清楚,漂亮的互动效果才不会更新错卡片。

这篇主要看哪个文件

打开:

entry/src/main/ets/entryformability/EntryFormAbility.ets

它里面有几个核心生命周期:

  • onAddForm():添加卡片时调用。
  • onUpdateForm():系统请求刷新时调用。
  • onFormEvent():普通卡片发消息时调用。
  • onRemoveForm():移除卡片时调用。
  • onAcquireFormState():返回卡片状态。

这一篇重点看onAddForm()onRemoveForm()

onAddForm 做了什么

项目里的代码核心是:

onAddForm(want:Want):formBindingData.FormBindingData{letformId:string='';letformWidth:number=-1;letformHeight:number=-1;if(want.parameters){formId=want.parameters['ohos.extra.param.key.form_identity']asstring;letformName=want.parameters['ohos.extra.param.key.form_name']asstring;letformDimension=want.parameters['ohos.extra.param.key.form_dimension']asstring;formWidth=want.parameters['ohos.extra.param.key.form_width']asnumber;formHeight=want.parameters['ohos.extra.param.key.form_height']asnumber;letformInfo=newFormInfo();formInfo.formId=formId;formInfo.formDimension=formDimension;formInfo.formName=formName;FormUtils.insertFormData(this.context,formInfo);if(formName.includes('Music')){FormUtils.updateMusicControlCard(formId,true);}}returnformBindingData.createFormBindingData({formId:formId,formWidth:formWidth,formHeight:formHeight});}

小白先别慌,拆开看。

第一步:从 want 里拿系统参数

添加卡片时,系统会把参数放进want.parameters。项目取了这些字段:

formId=want.parameters['ohos.extra.param.key.form_identity']asstring;letformName=want.parameters['ohos.extra.param.key.form_name']asstring;letformDimension=want.parameters['ohos.extra.param.key.form_dimension']asstring;

这三个最重要。

  • formId:系统给这张卡片分配的唯一 ID。
  • formName:卡片名称,比如MusicCard
  • formDimension:卡片尺寸,比如2*4

formId是后续更新卡片的钥匙。没有它,formProvider.updateForm()就不知道更新谁。

第二步:保存 FormInfo

项目创建了一个FormInfo

letformInfo=newFormInfo();formInfo.formId=formId;formInfo.formDimension=formDimension;formInfo.formName=formName;

然后交给FormUtils

FormUtils.insertFormData(this.context,formInfo);

FormUtils内部会调用FormRdbHelper,把这条卡片实例保存到 RDB。

为什么不用数组保存?

因为 Ability 生命周期可能被系统回收。内存数组没了,桌面卡片还在。RDB 更靠谱。

第三步:音乐卡片特殊处理

项目里有一段:

if(formName.includes('Music')){FormUtils.updateMusicControlCard(formId,true);}

这段是为了解决一个实际问题:新添加的音乐卡片不知道当前播放状态。

所以添加音乐卡片后,先给这张卡片下发:

isNeedRequestUpdate:true

音乐卡片页面里监听到这个字段变化后,会主动向应用请求当前播放数据。

这就是一个很实用的设计:新增卡片不直接猜状态,而是主动请求同步。

返回初始化数据

onAddForm()最后返回:

returnformBindingData.createFormBindingData({formId:formId,formWidth:formWidth,formHeight:formHeight});

这些数据会被普通卡片页面通过@LocalStorageProp接收。

比如你可以在卡片里写:

@LocalStorageProp('formId')formId:string='';@LocalStorageProp('formWidth')formWidth:number=0;@LocalStorageProp('formHeight')formHeight:number=0;

字段名必须一致。返回里叫formId,卡片里也要叫formId

onRemoveForm 也别忘了

添加时保存,删除时就要清理:

onRemoveForm(formId:string):void{FormUtils.deleteFormInfo(this.context,formId);}

这段很短,但很重要。

如果不删除,数据库里会残留已经不存在的卡片。后面批量更新时,可能会尝试更新一个已经被移除的formId,日志里就会出现各种失败。

小白可以自己写一个最小版

如果你想练习,可以先写一个简化版:

import{formBindingData,FormExtensionAbility}from'@kit.FormKit';importWantfrom'@ohos.app.ability.Want';exportdefaultclassEntryFormAbilityextendsFormExtensionAbility{onAddForm(want:Want):formBindingData.FormBindingData{constparams=want.parameters??{};constformId=params['ohos.extra.param.key.form_identity']asstring;constformName=params['ohos.extra.param.key.form_name']asstring;constformDimension=params['ohos.extra.param.key.form_dimension']asstring;console.info(`add form:${formId},${formName},${formDimension}`);returnformBindingData.createFormBindingData({formId,formName,formDimension});}onRemoveForm(formId:string):void{console.info(`remove form:${formId}`);}}

先用这个确认生命周期能跑,再接入项目里的FormUtilsFormRdbHelper

排查清单

如果onAddForm()没按预期执行,按这个顺序查:

  1. module.json5是否注册了EntryFormAbility,类型是不是form
  2. form_config.json的普通卡片是否配置正确。
  3. Index.ets添加卡片时abilityName是否写EntryFormAbility
  4. want.parameters里有没有form_identityform_nameform_dimension
  5. FormUtils.insertFormData()是否执行成功。

写在最后

EntryFormAbility不写复杂 UI,但它非常关键。它负责把“桌面上的卡片实例”变成项目里可查询、可更新、可删除的数据。

记住一句话:想让卡片后续能刷新,先把formId保存好。