鸿蒙技术分享:鸿蒙页面里更新卡片也太麻烦了吧!!!

🎉🎉🎉怎么简单地在鸿蒙页面内直接更新卡片数据???

服务卡片介绍

Form Kit简介

更新分类

服务卡片有静态卡片和动态卡片之分,而动态卡片的更新逻辑又分为自动更新和手动更新两大类。

  • 定时刷新
  • 定点刷新
  • 下次刷新
  • 代理刷新(最新版本API已不建议使用)
  • 卡片主动更新
  • 页面主动更新

列表前三种其实都是卡片自动更新逻辑,走FormExtensionAbility的onUpdateForm方法。

列表的后三种主要是为了实现在卡片之外的代码中主动刷新的逻辑,比如:

1.在卡片上点击了按钮后,更新卡片背景色;

2.在页面中设置卡片背景色,保存后,更新卡片背景色;

卡片主动更新的逻辑可以直接参考官方文档的通过message事件刷新卡片内容和通过router或call事件刷新卡片内容。

而页面主动更新的逻辑在官方文档里并没有明确而详细的说明,本文主要是讲解这部分。

页面主动更新

在页面中更新卡片和通过message事件更新卡片一样,都需要通过formProvider.updateForm()方法来进行,只不过区别在于,message事件触发onFormEvent(formId: string, message: string)事件,携带了formId参数。

而在页面中更新卡片时并不知道你要更新的formId参数。

所以页面主动更新的场景,主要就是解决怎么获取formId参数的事情。

获取formId参数

系统的FormExtensionAbility并没有提供卡片添加到桌面的成功回调方法,所以没办法通过回调直接获取formId。

FormExtensionAbility中是定义了onAddForm方法,但该方法是在添加卡片创建卡片预览时调用的,实际上应该是onCreateForm。

同时,FormExtensionAbility中还定义了onRemoveForm方法,该方法应该是onDestroyForm,也就是卡片销毁时调用。

所以,当你往桌面添加卡片时,所有的卡片都会触发onAddForm方法,除了成功添加的卡片之外的卡片都会触发onRemoveForm方法。

因此我们可以根据这一逻辑,获取到最终添加到桌面的卡片formId,我们可以保存在preferences中,以备使用。

详情参考以下代码,可以直接拷贝,在项目中继承EasyFormExtensionAbility:

TypeScript 复制代码
export interface EasyFormParam {
  identity: string;
  dimension: number;
  name: string;
  moduleName: string;
  width: number;
  height: number;
  temporary: boolean;
  abilityName: string;
  bundleName: string;
  launchReason: string;
  paramFormCustomize: string;
  formRenderingMode: string;
  hostBgInverseColor: string;
}

export abstract class EasyFormExtensionAbility extends FormExtensionAbility {
  preferences?: preferences.Preferences = undefined

  onAddForm(want: Want): formBindingData.FormBindingData {
    console.debug(`[卡片]onAddForm`)
    const formId = want.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string
    let param: EasyFormParam = {
      identity: want.parameters?.[formInfo.FormParam.IDENTITY_KEY] as string,
      dimension: want.parameters?.[formInfo.FormParam.DIMENSION_KEY] as number,
      name: want.parameters?.[formInfo.FormParam.NAME_KEY] as string,
      moduleName: want.parameters?.[formInfo.FormParam.MODULE_NAME_KEY] as string,
      width: want.parameters?.[formInfo.FormParam.WIDTH_KEY] as number,
      height: want.parameters?.[formInfo.FormParam.HEIGHT_KEY] as number,
      temporary: want.parameters?.[formInfo.FormParam.TEMPORARY_KEY] as boolean,
      abilityName: want.parameters?.[formInfo.FormParam.ABILITY_NAME_KEY] as string,
      bundleName: want.parameters?.[formInfo.FormParam.BUNDLE_NAME_KEY] as string,
      launchReason: want.parameters?.[formInfo.FormParam.LAUNCH_REASON_KEY] as string,
      paramFormCustomize: want.parameters?.[formInfo.FormParam.PARAM_FORM_CUSTOMIZE_KEY] as string,
      formRenderingMode: want.parameters?.[formInfo.FormParam.FORM_RENDERING_MODE_KEY] as string,
      hostBgInverseColor: want.parameters?.[formInfo.FormParam.HOST_BG_INVERSE_COLOR_KEY] as string,
    }
    this.preferences = preferences.getPreferencesSync(this.context, { name: 'EasyFormExtensionAbility' })
    this.preferences.putSync(formId, param)
    let list = this.preferences.getSync('formIdList', new Array()) as Array<string>
    list.push(formId)
    this.preferences.putSync('formIdList', list)
    this.preferences.flush()
    // 系统框架的onAddForm实质上是在form创建时调用,这里对名称进行更改,符合原始意图
    return this.onCreateFormEasy(formId, param)
  }
  abstract onCreateFormEasy(formId: string, formParam: EasyFormParam): formBindingData.FormBindingData
  onAddFormEasy(formId: string, formParam: EasyFormParam): void {

  }

  onRemoveForm(formId: string): void {
    console.debug(`[卡片]onRemoveForm`)
    this.preferences = preferences.getPreferencesSync(this.context, { name: 'EasyFormExtensionAbility' })
    let param = this.preferences.getSync(formId, undefined) as EasyFormParam
    this.onRemoveFormEasy(formId, param)
    this.preferences.deleteSync(formId)
    let list = this.preferences.getSync('formIdList', new Array()) as Array<string>
    list.splice(list.indexOf(formId), 1)
    this.preferences.putSync('formIdList', list)
    this.preferences.flush()
  }
  onRemoveFormEasy(formId: string, formParam: EasyFormParam): void {

  }
}

更新卡片

在页面内更新卡片时,通过preferences获取到所有已添加到桌面的formId列表。

然后遍历,根据你需要的服务卡片名称,获取到你需要的formId。

然后根据此formId调用formProvider.updateForm更新卡片数据。

详情参考以下代码:

TypeScript 复制代码
              let pref = preferences.getPreferencesSync(getContext(this), { name: 'EasyFormExtensionAbility' })
              let list = pref.getSync('formIdList', new Array()) as Array<string>
              let formId: string = '';
              list.forEach(element => {
                let param = pref.getSync(element, undefined) as EasyFormParam
                if (param.name === 'service_card_name') {
                  formId = element
                }
              });
              let info: Record<string, string> = { 'backgroundColor': this.backgroundColor }
              try {
                class FormDataClass {
                  info: Record<string, string> = info
                }
                let formData = new FormDataClass();
                let obj: formBindingData.FormBindingData = formBindingData.createFormBindingData(formData);
                formProvider.updateForm(formId, obj, (error: BusinessError) => {
                  if (error) {
                    console.error(`callback error, code: ${error.code}, message: ${error.message})`);
                    return;
                  }
                  console.log(`formProvider updateForm success`);
                });
              } catch (error) {
                console.error(`catch error, code: ${(error as BusinessError).code}, message: ${(error as BusinessError).message})`);
              }

其他:

如果你的一种服务卡片可以在桌面上添加多个,每个有不同的数据,那么你需要自己判断每个formId的状态,区分进行更新。

总结

官方的FormKit在使用时真的是一言难尽,不但调试运行有很多问题,在API功能的可用性上也很难受。

最大的问题是,可能是因为早期服务卡片的开发不是推广重点,所以文档不全,你去找官方的技术支持人员,他会给你贴一个OpenHarmony的文档......

服务卡片更新确实是刚需,核心代码就是EasyFormExtensionAbility,大家可以直接拿去用,有问题直接在评论区交流。

相关推荐
贾伟康2 小时前
HarmonyOS API 26 嵌套 Navigation:getParent、父子栈边界与返回分发
harmonyos·arkts·navigation·嵌套路由·navpathstack
行者-全栈开发3 小时前
【鸿蒙心迹】多线程并发实战——TaskPool 与 Worker 选型与踩坑(HarmonyOS 7.x)
华为·harmonyos·多线程并发·worker·taskpool·线程通信·harmonyos 并发
OH_TPC5 小时前
@ohos/aki 源码解读(一):一行绑定背后,宏、模板与索引分发
harmonyos
贾伟康6 小时前
【解压时刻|13】HarmonyOS ArkTS 启动链路审计:从 EntryAbility、AppStore 到 Navigation 首屏
harmonyos·arkts·appstorage·应用启动·entryability
贾伟康7 小时前
【古诗词闯关|12】HarmonyOS ArkTS 单页组件拆分实战:降低题库、闯关与结果弹层耦合
harmonyos·arkts·状态管理·arkui·组件化
威哥爱编程8 小时前
模拟面试智能体开发实战 07:答完一题就点评一题,结构化输出给分建议,让每道题都变成复盘
python·agent·harmonyos
威哥爱编程9 小时前
模拟面试智能体开发实战 08:总评报告先过三道闸,防泄题防夸大防错建议,才敢发到候选人手上
python·agent·harmonyos
熊猫钓鱼>_>1 天前
普通用户视角的端侧智能体验手记【鸿蒙心迹】
开发语言·人工智能·华为·智能手机·性能优化·ai编程·harmonyos
KevinChaos1 天前
阳台小花园开发手记 05|HarmonyOS 7.0 互动卡片:动效进出衔接
华为·harmonyos
WHMONY1 天前
大一独立开发鸿蒙原生 AI Agent:聊聊我为什么死磕端侧模型与“技术平权”
harmonyos