坚果派由坚果创建,团队拥有 12 个华为 HDE,以及若干其他领域的三十余位万粉博主运营。 团队成员聚集在北京,上海,南京,深圳,广州,宁夏等地,欢迎合作。
首先铺垫两个基础知识:
1.为什么桌面卡片需要使用特殊机制来刷新?
主要有两个原因:第一是 OpenHarmonyOS Api9 的桌面卡片出于降低系统能耗的目的,被限制了只有 5 秒的活动时间。超过 5 秒以后桌面卡片的相关进程会被强制销毁,变成一个静态的页面。只有通过 router 机制、call 机制或者 message 机制拉起相关后台,才能再次进行卡片内容的刷新。
第二个原因是从实际的运行机制来说,桌面卡片实际上并不是应用主体的一部分,而是归属于 OpenHarmony 系统中的桌面应用所管理的一系列服务,桌面卡片与其对应的应用主体之间相互隔离,只能使用专门的接口来进行数据交互与页面管理。
每张卡片都有一个独立的 LocalStorage 可以用来存储页面级变量,但同一个 LocalStorage 的数据只能在 UIAbility 内部共享,对外隔离,UIAbility 无法直接访问。
桌面卡片刷新机制的本质就是通过专门的接口,改变特定桌面卡片的 LocalStorage 参数。以实现桌面卡片的 UI 更新。
2.router 机制、call 机制与 message 机制有什么不同?
这三个机制都可以用来刷新桌面卡片的,三种机制的数据都以 JSON 的格式进行配置,并使用**formBindingData.createFormBindingData()**函数构建数据对象。
主要区别在于:
router 机制会直接打开应用界面,效果有点像点击桌面图标。也可以带参数打开应用,直接进入应用内部的某个特定位置,或者触发某项功能。
call 机制是不打开应用界面,仅在后台拉起应用主体的 UIAbility,来执行 UIAbility 内部的相关代码。call 机制不受 5 秒时长的限制,可以先实现复杂且费时的数据加载,再提供给桌面卡片进行刷新。
message 机制则不涉及到应用的 UIAbility,只是拉起桌面卡片自己的 FormAbility,也可以刷新卡片,但仍然受 5 秒时长的限制,更适合轻量化的的实现卡片内容的刷新。
接下来进入正式讲解:
本案例使用 call 机制,通过拉起应用主体的方式来刷新卡片内容。
使用 call 机制刷新卡片的全流程主要分为 3 个阶段:
1.通过卡片的 postCardAction 接口触发 call 事件 →
2.call 事件拉起应用主体的后台,进行数据准备,通过 updateForm 接口执行刷新事件 →
3.卡片 page 页面接收到数据,更新卡片界面。
由于卡片与应用主体是独立运作的,并且一个应用可能会有多个应用卡片,应用其实并不知到是哪个卡片触发了 call 事件,所以我们需要把卡片 id 作为参数一起写入接口,让卡片的管理方能找到我们要刷新的卡片。
补全以后的全流程如下:
1.(卡片创建时)FormAbility 获取卡片的 FormID,将其作为参数交给卡片页面储存 →
2.卡片页面初始化自己的 FromID
3.(点击刷新时)卡片通过 postCardAction 接口触发 call 事件,将卡片的 FormID 与要执行的函数名 method 都作为参数提交,由系统启动对应应用的 UIAbility→
4.UIAbility 启动成功,通过预置的触发器执行 method 对应的函数,完成数据准备后通过 updateForm 接口将数据推送给卡片管理方 →
5.对应 FormID 的卡片检测并同步到数据变动,完成页面变更。
案例代码:
1.卡片创建时 FormAbility 获取 FormID,并交给卡片页面
import formBindingData from '@ohos.app.form.formBindingData'; import FormExtensionAbility from '@ohos.app.form.FormExtensionAbility'; export default class EntryFormAbility extends FormExtensionAbility { onAddForm(want) {//创建卡片时产生的want中包含FormID,需要再此处读取出来同步给LocalStorage。 let formId = want.parameters["ohos.extra.param.key.form_identity"]; let dataObj1 = { "formId": formId }; let obj1 = formBindingData.createFormBindingData(dataObj1); return obj1; } };
2.卡片页面初始化自己的 FromID
let storage = new LocalStorage(); @Entry(storage) @Component struct WidgetCard { @LocalStorageProp('formId') formId: string = '0';//在Form页面中使用@LocalStorageProp来进行FromID变量的初始化 }
3.卡片通过 postCardAction 接口触发 call 事件,让系统拉起应用后台的 pageAbility
let storage = new LocalStorage(); @Entry(storage) @Component struct WidgetCard { @LocalStorageProp ("formId") @Watch('firstFresh') formId:string='0'//此处使用一个watch装饰器,在FormID初始化完成后实现第一次的数据刷新。 @LocalStorageProp('text')movieName: string = '加载中...'; @LocalStorageProp('imgName')imgName: string = 'imageName'; firstFresh(){ console.log('卡片初始化') postCardAction(this, { "action": 'call', "abilityName": this.ABILITY_NAME, "params": { "method":"funA", "formId":this.formId, } }); } build() { Column() { Button('刷新') .height('15%') .onClick(() => { postCardAction(this, { "action": 'call',//call事件 "abilityName": 'EntryAbility',//指向目标应用的Ability "params": { "method":"funA",//UIAbility中注册的用于刷新卡片的事件 "formId":this.formId,//卡片自身的FormID } }); }) } }
4.pageAbility 启动,执行对应的函数,完成数据准备后通过 updateForm 接口将数据推送给卡片管理方
(数据来源于对应的 severless 服务器,为方便演示,severless 的安全机制设为了不做身份校验即可访问数据的形式)
注意:callee 监听事件必须要先申请"ohos.permission.KEEP_BACKGROUND_RUNNING"权限才能正常运行!!!
import UIAbility from '@ohos.app.ability.UIAbility'; import formBindingData from '@ohos.app.form.formBindingData'; import formProvider from '@ohos.app.form.formProvider'; import hilog from '@ohos.hilog'; import Window from '@ohos.window'; import abilityAccessCtrl from '@ohos.abilityAccessCtrl'; import {AGCCloudDB} from'../services/AGCCloudDB' import {AGCStorageReference} from'../services/Storage' import request from '@ohos.request'; import fs from '@ohos.file.fs'; export default class EntryAbility extends UIAbility { onCreate(want, launchParam) {//如果触发call事件时UIAbility未启动,会先执行onCreate再执行监听事件。如果触发Call事件时UIAbility已经在运行中则直接执行监听事件。 this.callee.on('funA',(str)=>{//监听器,检测到对应参数就执行回调函数 let params = JSON.parse(str.readString()) if (params.formId != undefined) { let formId = params.formId const agcCloudDB = AGCCloudDB.instance(this.context) agcCloudDB.init(this.context).then((res) => { let CloudDB = new AGCStorageReference(this.context) agcCloudDB.getMovie().then((allRecords) => {//从数据库获取数据组 let radomNumber = Math.floor(Math.random() * allRecords.length) CloudDB.getDownloadUrl(allRecords[radomNumber].movieName).then((url) => {//从数据组中随机抽取一项,获取对应的图片下载链接 let tempDir = this.context.getApplicationContext().tempDir; let tmpFile = tempDir + '/file' + Date.now(); request.downloadFile(this.context, {//将图片下载到本地,并得到本地的图片地址 url: url, filePath: tmpFile }).then((task) => { task.on('complete', function callback() { console.info('ArkTSCard download complete:' + tmpFile); let file; try { file = fs.openSync(tmpFile); } catch (e) { console.error(`openSync failed: ${JSON.stringify(e)}`); } console.log(JSON.stringify(allRecords)) let formData = {//进行数据打包 "text": allRecords[radomNumber].movieName, "imgName": allRecords[radomNumber].movieName, 'formImages': {}, } formData.formImages[allRecords[radomNumber].movieName]=file.fd//由于Image的刷新机制必须接受不同的值才能识别到image变化,因此movieName只能使用变量的形式写入。 let formInfo = formBindingData.createFormBindingData(formData)//创建FormBindingData对象 formProvider.updateForm(formId, formInfo) })//执行updateForm事件,刷新指定卡片。 task.on('fail', function callBack(err) {//数据准备失败时显示的内容 console.info('ArkTSCard download task failed. Cause:' + err); let formInfo = formBindingData.createFormBindingData({ 'text': '刷新失败,请重试' }) formProvider.updateForm(formId, formInfo) }) }) return null }) }) }) } }) } }
5.对应 FormID 的卡片收到新的数据,完成页面变更。
let storage = new LocalStorage(); @Entry(storage) @Component struct WidgetCard { @LocalStorageProp ("formId") @Watch('firstFresh') formId:string='0' @LocalStorageProp('text')movieName: string = '加载中...'; @LocalStorageProp('imgName')imgName: string = 'imageName'; //LocalStorageProp检测到text与imgName变量发生改变,单向同步最新的数据,并触发卡片页面的文本与图片刷新。 build() { Column() { Text(this.text) .fontSize('12vp') .textAlign(TextAlign.Center) .width('100%') .height('15%') Row() { Image('memory://' + this.imgName)//imgName变化以后image组件会自动寻找对应的图片进行加载 .width('50%') .height('50%') .margin('5%') }.alignItems(VerticalAlign.Center) .justifyContent(FlexAlign.Center) Button('刷新') .height('15%') .onClick(() => { postCardAction(this, { "action": 'call', "abilityName": 'EntryAbility', "params": { "method":"funA",//UIAbility中注册的用于刷新卡片的事件 "formId":this.formId, } }); }) } .width('100%').height('100%') .alignItems(HorizontalAlign.Center) .padding('5%') } }
postCardAction 接口 call 事件的写法如下:
updateForm 接口的写法如下:
为了能让大家更好的学习鸿蒙 (OpenHarmony) 开发技术,这边特意整理了《鸿蒙 (OpenHarmony)开发学习手册》,希望对大家有所帮助:
《鸿蒙(Harmony OS)开发学习手册》
入门必看:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.应用开发导读(ArKTS)
2.……
HarmonyOS概念:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.系统定义
2.技术框架
3.技术特性
4.系统安全
快速入门:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.基本概念
2.构建第一个ArkTS应用
3.…
开发基础知识:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS
9…
基于ArkTS 开发:https://docs.qq.com/doc/DUk51cHZJaUpmSlhH
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16………
审核编辑 黄宇
-
鸿蒙
+关注
关注
57文章
2339浏览量
42805 -
HarmonyOS
+关注
关注
79文章
1973浏览量
30143 -
OpenHarmony
+关注
关注
25文章
3713浏览量
16254
发布评论请先 登录
相关推荐
评论