当前位置:   article > 正文

HarmonyOS实战开发-实现一个计步器卡片应用_harmony系统运动怎么添加计时器

harmony系统运动怎么添加计时器

介绍

本篇Codelab基于Stage模型实现带有卡片的计步应用,用于介绍卡片的开发及生命周期实现。需要完成以下功能:

  1. 消息通知栏,通知用户今天所行走步数。
  2. 元服务卡片,在桌面上添加2x2或2x4规格元服务卡片,能看到步数变化,也能看到当天所行走的进度。
  3. 关系型数据库,用于查询,添加用户行走的数据。

相关概念

  • 消息通知:提供通知管理的能力,包括发布、取消发布通知,创建、获取、移除通知通道,订阅、取消订阅通知,获取通知的使能状态、角标使能状态,获取通知的相关信息等。
  • 关系型数据库:关系型数据库基于SQLite组件提供了一套完整的对本地数据库进行管理的机制,对外提供了一系列的增、删、改、查等接口,也可以直接运行用户输入的SQL语句来满足复杂的场景需要。
  • 元服务卡片开发:卡片是一种界面展示形式,可以将应用的重要信息或操作前置到卡片,以达到服务直达、减少体验层级的目的。
  • 卡片提供方:显示卡片内容,控制卡片布局以及控件点击事件。
  • 卡片使用方:显示卡片内容的宿主应用,控制卡片在宿主中展示的位置。
  • 卡片管理服务:用于管理系统中所添加卡片的常驻代理服务,包括卡片对象的管理与使用,以及卡片周期性刷新等。

环境搭建

软件要求

  • DevEco Studio版本:DevEco Studio 3.1 Release。
  • OpenHarmony SDK版本:API version 9。

硬件要求

  • 开发板类型:润和RK3568开发板。
  • OpenHarmony系统:3.2 Release。

环境搭建

完成本篇Codelab我们首先要完成开发环境的搭建,本示例以RK3568开发板为例,参照以下步骤进行:

  1. 获取OpenHarmony系统版本:标准系统解决方案(二进制)。以3.2 Release版本为例:

2.搭建烧录环境。

  1. 完成DevEco Device Tool的安装
  2. 完成RK3568开发板的烧录

3.搭建开发环境。

  1. 开始前请参考工具准备,完成DevEco Studio的安装和开发环境配置。
  2. 开发环境配置完成后,请参考使用工程向导创建工程(模板选择“Empty Ability”)。
  3. 工程创建完成后,选择使用真机进行调测。

代码结构解读

本篇Codelab只对核心代码进行讲解。

  1. ├──entry/src/main/ets // 代码区
  2. │ ├──common
  3. │ │ ├──constants
  4. │ │ │ └──CommonConstants.ets // 常量类
  5. │ │ ├──database
  6. │ │ │ ├──Form.ets // 数据库卡片操作
  7. │ │ │ └──SensorData.ets // 数据库行走步数操作
  8. │ │ └──utils
  9. │ │ ├──ChartDataUtils.ets // 图表数据操作工具类
  10. │ │ ├──DatabaseUtils.ets // 数据库工具类
  11. │ │ ├──DateUtils.ets // 日期工具类
  12. │ │ ├──GlobalContext.ets // 项目工具类
  13. │ │ └──Logger.ets // 日志打印工具类
  14. │ ├──entryability
  15. │ │ └──EntryAbility.ets // 程序入口类
  16. │ ├──entryformability
  17. │ │ └──EntryFormAbility.ets // 卡片创建,更新,删除操作类
  18. │ ├──pages
  19. │ │ └──MainPage.ets // 主界面
  20. │ └──viewmodel
  21. │ ├──ChartPoint.ets // 图表点类
  22. │ ├──ChartValues.ets // 图表值类
  23. │ ├──FormData.ets // 表单数据类
  24. │ └──PointStyle.ets // 图表点样式类
  25. ├──entry/src/main/js // js代码区
  26. │ ├──card2x2 // 2x2卡片目录
  27. │ ├──card2x4 // 2x4卡片目录
  28. │ ├──common // 卡片资源目录
  29. │ └──i18n // 卡片国际化目录
  30. └──entry/src/main/resources // 资源文件目录

关系型数据库

元服务卡片需要用数据库保存不同时间、不同卡片的数据,而且在添加多张卡片情况下,需要保持数据同步刷新。因此需要创建两张表,一张是保存卡片信息,另一张是记录当天行走步数。

1.数据库创建使用的SQLite。

  1. // CommonConstants.ets
  2. // 表单SQLite
  3. static readonly CREATE_TABLE_FORM: string = 'CREATE TABLE IF NOT EXISTS Form ' +
  4. '(id INTEGER PRIMARY KEY AUTOINCREMENT, formId TEXT NOT NULL, formName TEXT NOT NULL, dimension INTEGER)';
  5. // 行走步数SQLite
  6. static readonly CREATE_TABLE_SENSOR_DATA: string = 'CREATE TABLE IF NOT EXISTS SensorData ' +
  7. '(id INTEGER PRIMARY KEY AUTOINCREMENT, date TEXT NOT NULL, stepsValue INTEGER)';

2.在EntryAbility的onCreate方法通过DatabaseUtils.createRdbStore方法创建数据库,并创建相应的表。

  1. // EntryAbility.ets
  2. onCreate(want: Want, param: AbilityConstant.LaunchParam): void {
  3. GlobalContext.getContext().setObject('abilityWant', want);
  4. GlobalContext.getContext().setObject('abilityParam', param);
  5. DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => {
  6. // 添加前三天行走模拟数据
  7. DatabaseUtils.addSimulationData(rdbStore as DataRdb.RdbStore);
  8. }).catch((error: Error) => {
  9. ...
  10. });
  11. }

消息通知

需要在MainPage的aboutToAppear调用requestNotification方法申请通知栏权限,效果如图所示:

  1. // MainPage.ets
  2. aboutToAppear() {
  3. // 申请通知栏权限
  4. this.requestNotification();
  5. ...
  6. }
  7. requestNotification() {
  8. Notification.requestEnableNotification().then(() => {
  9. ...
  10. }).catch((err: Error) => {
  11. ...
  12. });
  13. }

通过aboutToAppear的setInterval方法开启定时器,当定时器到10秒后,通过DatabaseUtils.sendNotifications方法发送消息到通知栏。效果如图所示:

  1. // DatabaseUtils.ets
  2. // 发送通知
  3. sendNotifications(stepsValue: string, notificationId: number) {
  4. // 获取当前系统语言
  5. let notificationBarTitle: string;
  6. let Language: string = I18n.System.getSystemLanguage();
  7. // 判断是否为中文
  8. if (Language.match(CommonConstants.CHINESE_LANGUAGE)) {
  9. notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_ZH +
  10. stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_ZH;
  11. } else {
  12. notificationBarTitle = CommonConstants.NOTIFICATIONS_TITLE_GONE_TODAY_EN +
  13. stepsValue + CommonConstants.NOTIFICATIONS_TITLE_STEPS_EN;
  14. }
  15. // 发布NotificationRequest.
  16. Notification.publish({
  17. id: CommonConstants.NOTIFICATIONS_ID,
  18. content: {
  19. contentType: Notification.ContentType.NOTIFICATION_CONTENT_BASIC_TEXT,
  20. normal: {
  21. title: notificationBarTitle,
  22. text: ''
  23. }
  24. }
  25. }).then(() => {
  26. ...
  27. });
  28. }

元服务卡片

使用元服务卡片分为四步:创建、初始化、更新、删除。

创建元服务卡片目录

  1. 在main目录下,点击鼠标右键 > New > Service Widget。

2.然后选择第一个选项下面带有Hello World字样,点击下一步Next。

3.填写卡片名字(Service widget name)、卡片介绍(Description)、是否开启低代码开发(Enable Super Visual)、开发语言(ArkTS和JS)、支持卡片规格(Support dimension)、关联表单(Ability name)点击Finish完成创建。如需创建多个卡片目录重新按照步骤1执行。

4.创建完卡片后,同级目录出现js目录,然后开发者在js目录下使用hml+css+json开发js卡片页面。

初始化元服务卡片

应用选择添加元服务卡片到桌面后,在EntryFormAbility的onAddForm方法进行卡片初始化操作,效果如图所示:

  1. // EntryFormAbility.ets
  2. onAddForm(want: Want) {
  3. let formId: string = want.parameters !== undefined ?
  4. want.parameters[CommonConstants.FORM_PARAM_IDENTITY_KEY] as string : '';
  5. let formName: string = want.parameters !== undefined ?
  6. want.parameters[CommonConstants.FORM_PARAM_NAME_KEY] as string : '';
  7. let dimensionFlag: number = want.parameters !== undefined ?
  8. want.parameters[CommonConstants.FORM_PARAM_DIMENSION_KEY] as number : 0;
  9. // 创建数据库
  10. DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => {
  11. // 存储卡片信息
  12. let form: Form = new Form();
  13. form.formId = formId;
  14. form.formName = formName;
  15. form.dimension = dimensionFlag;
  16. ...
  17. DatabaseUtils.insertForm(form, rdbStore as DataRdb.RdbStore);
  18. getToDaySteps(rdbStore as DataRdb.RdbStore, dimensionFlag, formId);
  19. }).catch((error: Error) => {
  20. ...
  21. });
  22. ...
  23. // 初始化卡片数据
  24. let formData: FormData = new FormData();
  25. formData.percent = 0;
  26. formData.steps = 0;
  27. return FormBindingData.createFormBindingData(formData);
  28. };

更新元服务卡片

1.初始化加载主页面布局之前,在MainPage的aboutToAppear方法中,调用setInterval方法开启定时器。时间到则先通过DatabaseUtils.insertValues方法把步数插入到数据库,再通过DatabaseUtils.updateForms方法更新卡片步数。

  1. // MainPage.ets
  2. aboutToAppear() {
  3. ...
  4. DatabaseUtils.getSensorData(rdbStoreValue, DateUtils.getDate(0))
  5. .then((sensorData: SensorData) => {
  6. if (sensorData) {
  7. this.stepsValue = sensorData.stepsValue;
  8. }
  9. // 开启定时器
  10. this.intervalId = setInterval(() => {
  11. ...
  12. DatabaseUtils.insertValues(this.stepsValue, rdbStoreValue);
  13. DatabaseUtils.updateForms(this.stepsValue, rdbStoreValue);
  14. }, CommonConstants.INTERVAL_DELAY_TIME);
  15. ...
  16. });
  17. }
  18. // DatabaseUtils.ets
  19. updateForms(stepValue: number, rdbStore: DataRdb.RdbStore) {
  20. let predicates: DataRdb.RdbPredicates =
  21. new DataRdb.RdbPredicates(CommonConstants.TABLE_FORM);
  22. // 查询卡片
  23. rdbStore.query(predicates).then((resultSet: DataRdb.ResultSet) => {
  24. ...
  25. // 查询第一行
  26. resultSet.goToFirstRow();
  27. do {
  28. let formId: string = resultSet.getString(resultSet.getColumnIndex(CommonConstants.FIELD_FORM_ID));
  29. let dimension: number = resultSet.getLong(resultSet.getColumnIndex(CommonConstants.FIELD_DIMENSION));
  30. ChartDataUtils.getFormData(formId, stepValue, dimension, rdbStore)
  31. .then((formData: FormData) => {
  32. // 更新多张卡片
  33. FormProvider.updateForm(formData.formId, FormBindingData.createFormBindingData(formData))
  34. .catch((error: Error) => {
  35. ...
  36. });
  37. }).catch((error: Error) => {
  38. ...
  39. });
  40. } while (resultSet.goToNextRow());
  41. resultSet.close();
  42. }).catch((error: Error) => {
  43. ...
  44. });
  45. }

2.卡片添加到桌面后,在EntryFormAbility的onAddForm方法中,调用formProvider.setFormNextRefreshTime方法设置倒计时。时间到了则通过updateSensorData方法更新卡片步数。

  1. // EntryFormAbility.ets
  2. onAddForm(want: Want) {
  3. ...
  4. // 五分钟倒计时
  5. formProvider.setFormNextRefreshTime(formId, CommonConstants.FIVE_MINUTES, (error, data) => {
  6. ...
  7. });
  8. }
  9. onUpdateForm(formId: string) {
  10. // 更新步数
  11. this.updateSensorData();
  12. ...
  13. }
  14. updateSensorData() {
  15. DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => {
  16. ...
  17. // 获取今天步数
  18. let getSensorData: Promise<SensorData> =
  19. DatabaseUtils.getSensorData(rdbStore as DataRdb.RdbStore, DateUtils.getDate(0));
  20. getSensorData.then((sensorData: SensorData) => {
  21. let stepValue: number = 0;
  22. if (sensorData) {
  23. stepValue = sensorData.stepsValue;
  24. }
  25. // 更新卡片数据
  26. DatabaseUtils.updateForms(stepValue, rdbStore);
  27. }).catch((error: Error) => {
  28. ...
  29. });
  30. }).catch((error: Error) => {
  31. ...
  32. });
  33. }

3.通过src/main/resources/base/profile/form_config.json配置文件,根据updateDuration或者scheduledUpdateTime字段配置刷新时间。updateDuration优先级高于scheduledUpdateTime,两者同时配置时,以updateDuration配置的刷新时间为准。当配置的刷新时间到了,系统调用onUpdateForm方法进行更新。

  1. // form_config.json
  2. {
  3. // 卡片的类名
  4. "name": "card2x2",
  5. // 卡片的描述
  6. "description": "This is a service widget.",
  7. // 卡片对应完整路径
  8. "src": "./js/card2x2/pages/index/index",
  9. // 定义与显示窗口相关的配置
  10. "window": {
  11. "designWidth": 720,
  12. "autoDesignWidth": true
  13. },
  14. // 卡片的主题样式
  15. "colorMode": "auto",
  16. // 是否为默认卡片
  17. "isDefault": true,
  18. // 卡片是否支持周期性刷新
  19. "updateEnabled": true,
  20. // 采用24小时制,精确到分钟
  21. "scheduledUpdateTime": "00:00",
  22. // 当取值为0时,表示该参数不生效,当取值为正整数N时,表示刷新周期为30*N分钟。
  23. "updateDuration": 1,
  24. // 卡片默认外观规格
  25. "defaultDimension": "2*2",
  26. // 卡片支持外观规格
  27. "supportDimensions": [
  28. "2*2"
  29. ]
  30. }
  31. // EntryFormAbility.ets
  32. onUpdateForm(formId: string) {
  33. // 更新步数
  34. updateSensorData();
  35. ...
  36. }

删除元服务卡片

当用户需要删除元服务卡片时,可以在EntryFormAbility的onRemoveForm方法中,通过DatabaseUtils.deleteFormData方法删除数据库中对应的卡片信息。

  1. // EntryFormAbility.ets
  2. onRemoveForm(formId: string) {
  3. DatabaseUtils.createRdbStore(this.context).then((rdbStore: Object | undefined) => {
  4. ...
  5. // 删除数据库中对应的卡片信息
  6. DatabaseUtils.deleteFormData(formId, rdbStore as DataRdb.RdbStore);
  7. }).catch((error: Error) => {
  8. ...
  9. });
  10. }
  11. // DatabaseUtils.ets
  12. deleteFormData(formId: string, rdbStore: DataRdb.RdbStore) {
  13. let predicates: DataRdb.RdbPredicates = new DataRdb.RdbPredicates(CommonConstants.TABLE_FORM);
  14. predicates.equalTo(CommonConstants.FIELD_FORM_ID, formId);
  15. rdbStore.delete(predicates).catch((error: Error) => {
  16. ...
  17. });
  18. }

总结

您已经完成了本次Codelab的学习,并了解到以下知识点:

  1. 使用notification发布通知。
  2. 使用关系型数据库插入、更新、删除卡片数据。
  3. 使用FormExtensionAbility创建、更新、删除元服务卡片

为了帮助大家更深入有效的学习到鸿蒙开发知识点,小编特意给大家准备了一份全套最新版的HarmonyOS NEXT学习资源,获取完整版方式请点击→HarmonyOS教学视频

HarmonyOS教学视频:语法ArkTS、TypeScript、ArkUI等…视频教程

鸿蒙生态应用开发白皮书V2.0PDF:

获取完整版白皮书方式请点击→《鸿蒙生态应用开发白皮书V2.0PDF

在这里插入图片描述

鸿蒙 (Harmony OS)开发学习手册

一、入门必看

  1. 应用开发导读(ArkTS)
  2. .……

在这里插入图片描述


二、HarmonyOS 概念

  1. 系统定义
  2. 技术架构
  3. 技术特性
  4. 系统安全

在这里插入图片描述

三、如何快速入门?鸿蒙基础入门学习指南

  1. 基本概念
  2. 构建第一个ArkTS应用
  3. .……

在这里插入图片描述


四、开发基础知识

  1. 应用基础知识
  2. 配置文件
  3. 应用数据管理
  4. 应用安全管理
  5. 应用隐私保护
  6. 三方应用调用管控机制
  7. 资源分类与访问
  8. 学习ArkTS语言
  9. .……

在这里插入图片描述


五、基于ArkTS 开发

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 7.网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. .……

在这里插入图片描述


更多了解更多鸿蒙开发的相关知识可以参考:《鸿蒙 (Harmony OS)开发学习手册

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/567198
推荐阅读
相关标签
  

闽ICP备14008679号