首页 > 其他分享 >学习服务卡片事件能力

学习服务卡片事件能力

时间:2023-09-25 12:05:39浏览次数:39  
标签:console 卡片 detail 学习 params 事件 let message

【本文正在参加 2023「盲盒」+码有奖征文活动】,活动链接 https://ost.51cto.com/posts/25284

简要介绍

ArkTS卡片内部和提供方应用间的交互,可以通过在卡片一端调用postCardAction来实现,当前支持router、message和call三种类型的事件。我们根据实际应用分别从五个方面简单学习一下:

  1. 服务卡片通过router跳转到应用指定页面;
  2. 服务卡片通过call调用应用页面在后台执行;
  3. 应用通过message事件刷新服务卡片内容;
  4. 应用通过router事件刷新服务卡片内容;
  5. 应用通过call事件刷新服务卡片内容;

为了充分理解和使用这五种能力,我计划新创建一个服务卡片,在上面放置5个按钮分别实现对应的功能,同时放置一个文本组件,用于显示事件刷新的结果。

  • 按钮“主页面”,点击后直接跳转到主页面;
  • 按钮“子页面”,点击后直接跳转到子页面;
  • 按钮“message+1”,点击后通过message方式刷新服务卡片,并使文本数值加一。
  • 按钮“call+2”,点击后通过call方式刷新服务卡片,并使文本数值加二。
  • 按钮“router+3”,点击后通过router方式刷新服务卡片,并使文本数值加三。

效果预览

anim.gif

详细介绍

1.跳转到页面

应用中一共有两个页面Index.ets与Second.ets,点击卡片上相应的按钮跳转到对应界面,主要是通过调用postCardAction向指定UIAbility发送router事件,并在事件内定义需要传递的内容targetPage,该参数用来标识要打开的page页面。

Button('主页面', { type: ButtonType.Normal, stateEffect: true })
  .borderRadius(8)
  .margin(2)
  .onClick(() => {
    postCardAction(this, {
      'action': 'router',
      'abilityName': 'EntryAbility',
      'params': {
        'targetPage': 'index'
      }
    });
  })

Button('子页面', { type: ButtonType.Normal, stateEffect: true })
  .borderRadius(8)
  .margin(1)
  .onClick(() => {
    postCardAction(this, {
      'action': 'router',
      'abilityName': 'EntryAbility',
      'params': {
        'targetPage': 'second'
      }
    });
  })

在EntryAbility.ts中接收router事件并获取参数,根据传递的params不同,设置参数selectPage,在onWindowStageCreate函数中,根据传入的不同值,通过windowStage.loadContent拉起不同的页面。

onCreate(want, launchParam) {
  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');

  if (want.parameters.params !== undefined) {
    let params = JSON.parse(want.parameters.params);
    console.info("onCreate router targetPage:" + params.targetPage);
    selectPage = params.targetPage;
  }
}


onNewWant(want, launchParam) {
  console.info("onNewWant want:" + JSON.stringify(want));
  if (want.parameters.params !== undefined) {
    let params = JSON.parse(want.parameters.params);
    console.info("onNewWant router targetPage:" + params.targetPage);
    selectPage = params.targetPage;
  }

  if (currentWindowStage != null) {
    this.onWindowStageCreate(currentWindowStage);
  }
}

onWindowStageCreate(windowStage: window.WindowStage) {
  // Main window is created, set main page for this ability
  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageCreate');

  let targetPage;
  // 根据传递的targetPage不同,选择拉起不同的页面
  switch (selectPage) {
    case 'index':
      targetPage = 'pages/Index';
      break;
    case 'second':
      targetPage = 'pages/Second';
      break;
    default:
      targetPage = 'pages/Index';
  }
  if (currentWindowStage === null) {
    currentWindowStage = windowStage;
  }

  windowStage.loadContent(targetPage, (err, data) => {
    if (err.code) {
      hilog.error(0x0000, 'testTag', 'Failed to load the content. Cause: %{public}s', JSON.stringify(err) ?? '');
      return;
    }
    hilog.info(0x0000, 'testTag', 'Succeeded in loading the content. Data: %{public}s', JSON.stringify(data) ?? '');
  });
}

2.调用应用到后台

在卡片中使用postCardAction接口的call能力,能够将卡片提供方应用的指定UIAbility拉到后台。同时,call能力提供了调用应用指定方法、传递数据的功能,使应用在后台运行时可以通过卡片上的按钮执行不同的功能。 我们在这个示例中,通过postCardAction的call方式,调用EntryAbility中的funA方法,在funA方法具体实现函数funACall中,对传递的值进行加二操作。在EntryAbility中,funA方法也要进行注册和注销。 卡片中调用postCardAction方法时,action参数应指定为call,同时参数表中必须带method参数。

Button('call+2', { type: ButtonType.Normal, stateEffect: true })
  .borderRadius(8)
  .margin(1)
  .onClick(() => {
    console.info('postCardAction to EntryAbility');
    postCardAction(this, {
      'action': 'call',
      'abilityName': 'EntryAbility', // 只能跳转到当前应用下的UIAbility
      'params': {
        'method': 'funA',
        'formId': this.formId,
        'detail': this.detail
      }
    });
  })

UIAbility需要onCreate生命周期中打开监听所需的方法,onDestroy生命周期中关闭监听所需的方法。

const MSG_SEND_METHOD: string = 'funA'

onCreate(want, launchParam) {
  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');

  try {
    // 监听call事件所需的方法
    this.callee.on(MSG_SEND_METHOD, FunACall);
  } catch (error) {
    console.log(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
  }
}

onDestroy() {
  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');

  try {
    this.callee.off(MSG_SEND_METHOD);
  } catch (error) {
    console.log(`${MSG_SEND_METHOD} register failed with error ${JSON.stringify(error)}`)
  }
}

在打开监听时,需要指定具体的实现函数。

function FunACall(data) {
  // 获取call事件中传递的所有参数
  let params = JSON.parse(data.readString())
  if (params.formId !== undefined) {
    let curFormId = params.formId;
    let message = params.detail;
    console.info(`UpdateForm formId: ${curFormId}, message: ${message}`);
    let formData = {
      "detail": (Number.parseInt(message) + 2).toString()
    };
    let formMsg = formBindingData.createFormBindingData(formData)
    formProvider.updateForm(curFormId, formMsg).then((data) => {
      console.info('updateForm success.' + JSON.stringify(data));
    }).catch((error) => {
      console.error('updateForm failed:' + JSON.stringify(error));
    })
  }
  return null;
}

这个功能通过call方式拉起指定UIAbility到后台,隐式的执行计算操作,后面的通过call刷新卡片功能就会用到这个。

==使用这个功能有两点必须要注意: 1.必须指定要拉起的UIAbility的launchType为singleton类型,否则无效; 2.必须添加权限 ohos.permission.KEEP_BACKGROUND_RUNNING,否则也无效;==

3.通过message刷新卡片

卡片页面中可以通过postCardAction接口触发message事件拉起FormExtensionAbility。 示例中,我们通过message的方式更新传递的值,并执行加一操作。

animmsg.gif

卡片中实现,

Button('message+1', { type: ButtonType.Normal, stateEffect: true })
  .borderRadius(8)
  .margin(1)
  .onClick(() => {
    console.info('postCardAction to EntryAbility');
    postCardAction(this, {
      'action': 'message',
      'params': {
        'detail': this.detail
      }
    });
  })

在FormExtensionAbility的onFormEvent生命周期中调用updateForm接口刷新卡片。

onFormEvent(formId, message) {
  // Called when a specified message event defined by the form provider is triggered.
  console.info(`FormAbility onEvent, formId = ${formId}, message: ${JSON.stringify(message)}`);

  let params = JSON.parse(message);
  let detail = '0'
  if (params.detail !== undefined) {
    detail = params.detail;
  }
  let formData = {
    'detail': (Number.parseInt(detail) + 1).toString()
  };
  let formInfo = formBindingData.createFormBindingData(formData)
  formProvider.updateForm(formId, formInfo).then((data) => {
    console.info('FormAbility updateForm success.' + JSON.stringify(data));
  }).catch((error) => {
    console.error('FormAbility updateForm failed: ' + JSON.stringify(error));
  })
}

4.通过router刷新卡片

卡片页面中可以通过postCardAction接口触发router事件拉起UIAbility,然后由UIAbility刷新卡片内容,此时会把page页面调用到前台。 示例中也是传递当前文本参数,然后打开新的页面,同时会更新传递的值并加三操作,然后再formProvider.updateForm反馈给卡片页面。 animrouter.gif

卡片中的实现:

Button('router+3', { type: ButtonType.Normal, stateEffect: true })
  .borderRadius(8)
  .margin(2)
  .onClick(() => {
    console.info('postCardAction to EntryAbility');
    postCardAction(this, {
      'action': 'router',
      'abilityName': 'EntryAbility',
      'params': {
        'detail': this.detail
      }
    });
  })

在UIAbility的onCreate()或者onNewWant()生命周期中可以通过入参want获取传递过来的参数信息,然后调用updateForm接口刷新卡片。

onCreate(want, launchParam) {
  hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onCreate');


  if (want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {
    let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
    // let detail = JSON.parse(want.parameters.params).detail;
    let detail = JSON.parse(want.parameters.params).detail;
    if (detail !== undefined) {
      console.info(`UpdateForm formId: ${curFormId}, message: ${detail}`);
      let formData = {
        "detail": (Number.parseInt(detail) + 3).toString()
      };
      let formMsg = formBindingData.createFormBindingData(formData)
      formProvider.updateForm(curFormId, formMsg).then((data) => {
        console.info('updateForm success.' + JSON.stringify(data));
      }).catch((error) => {
        console.error('updateForm failed:' + JSON.stringify(error));
      })
    }
  }

}

onNewWant(want, launchParam) {
  console.info("onNewWant want:" + JSON.stringify(want));

  if (want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {
    let curFormId = want.parameters[formInfo.FormParam.IDENTITY_KEY];
    let detail = JSON.parse(want.parameters.params).detail;
    if (detail !== undefined) {
      console.info(`UpdateForm formId: ${curFormId}, message: ${detail}`);
      let formData = {
        "detail": (Number.parseInt(detail) + 3).toString()
      };
      let formMsg = formBindingData.createFormBindingData(formData)
      formProvider.updateForm(curFormId, formMsg).then((data) => {
        console.info('updateForm success.' + JSON.stringify(data));
      }).catch((error) => {
        console.error('updateForm failed:' + JSON.stringify(error));
      })
    }
  }
}

5.通过call刷新卡片

通过call刷新卡片和之前的调用应用到后台方法类似,在调用后台的基础上加入了更新卡片的功能。

animcall.gif

在使用postCardAction接口的call事件时,需要在FormExtensionAbility中的onAddForm生命周期回调中更新formId。

export default class EntryFormAbility extends FormExtensionAbility {
  onAddForm(want) {
    // Called to return a FormBindingData object.
    // let formData = {};
    // return formBindingData.createFormBindingData(formData);

    // let formId = want.parameters["ohos.extra.param.key.form_identity"];
    // let dataObj1 = {
    //   "formId": formId
    // };
    // let obj1 = formBindingData.createFormBindingData(dataObj1);
    // return obj1;

    let formId = want.parameters["ohos.extra.param.key.form_identity"];
    let formData = {
      "formId": formId
    };
    return formBindingData.createFormBindingData(formData);

  }
}

服务卡片中的按钮就是之前的拉起后台的按钮,功能一样

  Button('call+2', { type: ButtonType.Normal, stateEffect: true })
    .borderRadius(8)
    .margin(1)
    .onClick(() => {
      console.info('postCardAction to EntryAbility');
      postCardAction(this, {
        'action': 'call',
        'abilityName': 'EntryAbility', // 只能跳转到当前应用下的UIAbility
        'params': {
          'method': 'funA',
          'formId': this.formId,
          'detail': this.detail
        }
      });
    })

具体实现是在UIAbility的onCreate生命周期中监听call事件回调的方法funACall,对传递进来的值加二更新,然后调用updateForm接口刷新卡片。

function FunACall(data) {
  // 获取call事件中传递的所有参数
  let params = JSON.parse(data.readString())
  if (params.formId !== undefined) {
    let curFormId = params.formId;
    let message = params.detail;
    console.info(`UpdateForm formId: ${curFormId}, message: ${message}`);
    let formData = {
      "detail": (Number.parseInt(message) + 2).toString()
    };
    let formMsg = formBindingData.createFormBindingData(formData)
    formProvider.updateForm(curFormId, formMsg).then((data) => {
      console.info('updateForm success.' + JSON.stringify(data));
    }).catch((error) => {
      console.error('updateForm failed:' + JSON.stringify(error));
    })
  }
  return null;
}

==和之前一样,要注意两点,指定要拉起的UIAbility的launchType为singleton类型,添加权限 ohos.permission.KEEP_BACKGROUND_RUNNING,否则无效;==

学习总结

服务卡片和应用之间的消息传递是经常要用的功能,服务卡片的数据更新也是必不可少的,鸿蒙一共提供了三种方式,我们可以根据需要选择合适的去使用,message方式是与FormExtensionAbility打交道,router和call是与UIAbility打交道。支持call方式时一定不要忘了,在module.json5中设置launchType和ohos.permission.KEEP_BACKGROUND_RUNNING。

附件链接:https://ost.51cto.com/resource/3034

本文作者:droidzxy

想了解更多关于开源的内容,请访问:​

​51CTO 开源基础软件社区​

​https://ost.51cto.com/#bkwz​

标签:console,卡片,detail,学习,params,事件,let,message
From: https://blog.51cto.com/harmonyos/7594253

相关文章

  • Java底层学习
    最近在看几本Java的书,也做了很多笔记,主要是关于Java虚拟机、JavaGC、Java并发编程等方面,参考的主要几本书籍有:《深入理解Java虚拟机》——周志明《深入理解Java虚拟机第二版》——美BillVenners《Java性能调优指南》——也是老美的《Java高并发程序设计》——葛一鸣本来想自己......
  • 机器学习笔记
    机器学习笔记mAP(meanAveragePrecision)在机器学习中的目标检测领域,是十分重要的衡量指标,用于衡量目标检测算法的性能。一般而言,全类平均正确率(mAP,又称全类平均精度)是将所有类别检测的平均正确率(AP)进行综合加权平均而得到的。李课理论部分损失函数(LossFunction)是定义在单个......
  • SDTM初学笔记 - [001] - SDTM基础概念学习
    SDTM,全称StudyDataTabulationModel,围绕着observations的概念构建,observations由研究期间收集的一些离散信息组成,通常对应于数据集中的rows。1Domains一个domain是关于一个特定topic的观测的集合。SDTM的首要目的是展示关于研究受试者的数据(可能是humans,或animals,或medical......
  • layui table 表格上下左右事件
    //按键监听事件$(document).on('keydown','.layui-input',function(event){vartd=$(this).parent('td');varindex=td.index();vartr=td.parent('tr');v......
  • 基于对数谱图的深度学习心音分类
    这是一篇很有意思的论文,他基于心音信号的对数谱图,提出了两种心率音分类模型,我们都知道:频谱图在语音识别上是广泛应用的,这篇论文将心音信号作为语音信号处理,并且得到了很好的效果。对心音信号进行一致长度的分帧,提取其对数谱图特征,论文提出了长短期记忆(LSTM)和卷积神经网络(CNN)......
  • 微积分 学习笔记
    1.函数,图形在高中,我们学过圆锥曲线,大学对它进行了拓展。要学习微积分,首先要先学习函数。在数学中,函数的定义是:给定两个集合\(S1,S2\),一个规则\(f\),对于每个\(S1\)中的元素\(x\),\(f\)都把它变化成\(S2\)中的元素。\(S2\)的所有元素都对应至少一个\(S1\)的元素。\(S1\)被称为定......
  • 3、深度学习入门之数值微分P94、P95、P96、P97、P98
    $f'(x)=\lim_{{\Deltax\to0}}\frac{f(x0+\Deltax)-f(x0)}{\Deltax}$$f(x0+\Deltax)-f(x0)=\Deltay$$f'(x) =\lim_{{\Deltax\to0}}\frac{\Deltay}{\Deltax}$$f'(x)$就是导数导数粗糙的理解为就是在某点的切线斜率可导意味着在某点处它的导数存在 ......
  • 学习笔记三
    sh编程sh脚本sh脚本是一个包含sh语句的文本文件,命令解释程序sh要执行该语句,所有的sh基本都执行相同的任务,脚本在语法上略有不同,shebang允许允许主sh调用适当版本的sh来执行脚本。如果未指定shebang,默认执行sh,即下列程序的第一行。例:创建一个一个文本文件mysh,包含:#!/bin/bash......
  • 树哈希学习笔记
    我们用字符串哈希可以判断字符串相等,那么判断树同构呢?两棵树同构,当且仅当存在将其中一棵树的节点打乱的方案,使得打乱后两棵树完全相同。树哈希,就是把字符串哈希搬到树上来。对于两棵同构的有根树,其哈希值相同。下面介绍一种构造方式。\[f_i=\sum\limits_{x\inson(i)}f_xp_{|......
  • 学习总结报告1
    不同目录下分别存哪些文件,如bin目录主要存命令,root目录下存放超级用户主,目录,Home是普通用户文件夹路径分为绝对路径和相对路径,绝对路径从根目录写,相对路径可以使用".."返回上一层目录,如"../man"就是到同级目录man文件使用"sumroot"进入超级管理员模式”"cd"为跳转命名,"mkdir"可......