文章目录效果图这篇主要看哪个文件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){formIdwant.parameters[ohos.extra.param.key.form_identity]asstring;letformNamewant.parameters[ohos.extra.param.key.form_name]asstring;letformDimensionwant.parameters[ohos.extra.param.key.form_dimension]asstring;formWidthwant.parameters[ohos.extra.param.key.form_width]asnumber;formHeightwant.parameters[ohos.extra.param.key.form_height]asnumber;letformInfonewFormInfo();formInfo.formIdformId;formInfo.formDimensionformDimension;formInfo.formNameformName;FormUtils.insertFormData(this.context,formInfo);if(formName.includes(Music)){FormUtils.updateMusicControlCard(formId,true);}}returnformBindingData.createFormBindingData({formId:formId,formWidth:formWidth,formHeight:formHeight});}小白先别慌拆开看。第一步从 want 里拿系统参数添加卡片时系统会把参数放进want.parameters。项目取了这些字段formIdwant.parameters[ohos.extra.param.key.form_identity]asstring;letformNamewant.parameters[ohos.extra.param.key.form_name]asstring;letformDimensionwant.parameters[ohos.extra.param.key.form_dimension]asstring;这三个最重要。formId系统给这张卡片分配的唯一 ID。formName卡片名称比如MusicCard。formDimension卡片尺寸比如2*4。formId是后续更新卡片的钥匙。没有它formProvider.updateForm()就不知道更新谁。第二步保存 FormInfo项目创建了一个FormInfoletformInfonewFormInfo();formInfo.formIdformId;formInfo.formDimensionformDimension;formInfo.formNameformName;然后交给FormUtilsFormUtils.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:number0;LocalStorageProp(formHeight)formHeight:number0;字段名必须一致。返回里叫formId卡片里也要叫formId。onRemoveForm 也别忘了添加时保存删除时就要清理onRemoveForm(formId:string):void{FormUtils.deleteFormInfo(this.context,formId);}这段很短但很重要。如果不删除数据库里会残留已经不存在的卡片。后面批量更新时可能会尝试更新一个已经被移除的formId日志里就会出现各种失败。小白可以自己写一个最小版如果你想练习可以先写一个简化版import{formBindingData,FormExtensionAbility}fromkit.FormKit;importWantfromohos.app.ability.Want;exportdefaultclassEntryFormAbilityextendsFormExtensionAbility{onAddForm(want:Want):formBindingData.FormBindingData{constparamswant.parameters??{};constformIdparams[ohos.extra.param.key.form_identity]asstring;constformNameparams[ohos.extra.param.key.form_name]asstring;constformDimensionparams[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});}}先用这个确认生命周期能跑再接入项目里的FormUtils和FormRdbHelper。排查清单如果onAddForm()没按预期执行按这个顺序查module.json5是否注册了EntryFormAbility类型是不是form。form_config.json的普通卡片是否配置正确。Index.ets添加卡片时abilityName是否写EntryFormAbility。want.parameters里有没有form_identity、form_name、form_dimension。FormUtils.insertFormData()是否执行成功。写在最后EntryFormAbility不写复杂 UI但它非常关键。它负责把“桌面上的卡片实例”变成项目里可查询、可更新、可删除的数据。记住一句话想让卡片后续能刷新先把formId保存好。