在 HarmonyOS 上使用 ArkUI 实现计步器应用

介绍

本篇 Codelab 使用 ArkTS 语言实现计步器应用,上使用I实应用主要包括计步传感器、现计定位服务和后台任务功能:

1.  通过订阅计步器传感器获取计步器数据,步器处理后显示。应用

2.  通过订阅位置服务获取位置数据,上使用I实处理后显示。现计

3.  通过服务开发实现后台任务功能。步器

相关概念

计步传感器 :订阅计步器传感器数据,应用系统返回相关数据。上使用I实

后台任务管理 :应用中存在用户能够直观感受到的现计且需要一直在后台运行的业务时(如,后台播放音乐),步器可以使用长时任务机制。应用

位置服务 :位置服务提供 GNSS 定位、上使用I实网络定位、现计地理编码、步器逆地理编码、国家码和地理围栏等基本功能。

相关权限

本篇 Codelab 用到了计步传感器、后台任务及位置服务功能,需要在配置文件 module.json5 里添加权限:

●  ohos.permission.ACTIVITY_MOTION

●  ohos.permission.KEEP_BACKGROUND_RUNNING

●  ohos.permission.APPROXIMATELY_LOCATION

●  ohos.permission.LOCATION

●  ohos.permission.LOCATION_IN_BACKGROUND

完整示例

gitee源码地址

源码下载

计步器应用(ArkTS).zip

环境搭建

我们首先需要完成 HarmonyOS 开发环境搭建,可参照如下步骤进行。

软件要求

DevEco Studio 版本:DevEco Studio 3.1 Release。服务器租用

HarmonyOS SDK 版本:API version 9。

硬件要求

设备类型:华为手机或运行在 DevEco Studio 上的华为手机设备模拟器。

HarmonyOS 系统:3.1.0 Developer Release。

环境搭建

安装 DevEco Studio,详情请参考 下载和安装软件 。

设置 DevEco Studio 开发环境,DevEco Studio 开发环境需要依赖于网络环境,需要连接上网络才能确保工具的正常使用,可以根据如下两种情况来配置开发环境:如果可以直接访问 Internet,只需进行 下载HarmonyOS SDK 操作。

如果网络不能直接访问 Internet,需要通过代理服务器才可以访问,请参考 配置开发环境 。

开发者可以参考以下链接,完成设备调试的相关配置: 使用真机进行调试

使用模拟器进行调试

代码结构解读

本篇 Codelab 只对核心代码进行讲解,对于完整代码,我们会在源码下载或 gitee 中提供。

├──entry/src/main/ets                // 代码区 │  ├──common │  │  ├──constants │  │  │  └── CommonConstants. ets      // 公共常量 │  │  └──utils                       // 日志类 │  │     ├── BackgroundUtil. ets       // 后台任务工具类 │  │     ├── GlobalContext. ets        // 首|选项工具类 │  │     ├── LocationUtil. ets         // 位置服务工具类 │  │     ├── Logger. ets               // 日志工具类 │  │     ├── NumberUtil. ets           // 数字处理工具类 │  │     └── StepsUtil. ets            // 计步器工具类 │  ├──entryability │  │  └── EntryAbility. ets            // 程序入口类 │  ├──pages │  │  └── HomePage. ets                // 应用首页 │  └──view │     ├── CompletionStatus. ets        // 目标设置页 │     ├── CurrentSituation. ets        // 计步信息页 │     └── InputDialog. ets             // 自定义弹窗 └──entry/src/main/resources          // 资源文件夹

构建应用界面

计步器页面主要由 Stack 堆叠容器组件、Component 自定义组件和 CustomDialog 自定义弹窗组件完成页面布局,效果如图所示:

// HomePage.ets build() {  Stack({ alignContent: Alignment.TopStart }) {    CompletionStatus({      progressValue: $progressValue    })    CurrentSituation({      currentSteps: this.currentSteps,      startPosition: this.startPosition,      currentLocation: this.currentLocation    })    Row() {      Button(this.isStart ? $r(app.string.stop) : $r(app.string.start))        ...    }    ...  }  ... }

计步传感器

应用启动后申请计步传感器权限,服务器托管获取权限后订阅计步器传感器。通过订阅获取到计步传感器数据,解析处理后在页面显示。效果如图所示:

// HomePage.ets requestPermissions(): void {  let atManager = abilityAccessCtrl.createAtManager();  try {    atManager.requestPermissionsFromUser(this.context, CommonConstants.REQUEST_PERMISSIONS).then((data) => {      if (data.authResults[0] !== 0 || data.authResults[1] !== 0) {        return;      }      const that = this;      try {        sensor.on(sensor.SensorId.PEDOMETER, (data) => {          try {            if (that.isStart) {              if (StepsUtil.checkStrIsEmpty(that.oldSteps)) {                that.oldSteps = data.steps.toString();                StepsUtil.putStorageValue(CommonConstants.OLD_STEPS, that.oldSteps);              } else {                that.currentSteps = (data.steps - NumberUtil._parseInt(that.oldSteps, 10)).toString();              }            } else {              that.currentSteps = data.steps.toString();            }            if (StepsUtil.checkStrIsEmpty(that.stepGoal) || !that.isStart) {              return;            }            StepsUtil.putStorageValue(CommonConstants.CURRENT_STEPS, that.currentSteps);            that.progressValue = StepsUtil.getProgressValue(NumberUtil._parseInt(that.stepGoal, 10),              NumberUtil._parseInt(that.currentSteps, 10));            StepsUtil.putStorageValue(CommonConstants.PROGRESS_VALUE_TAG, String(that.progressValue));          } catch (err) {            Logger.error(TAG, Sensor on err + JSON.stringify(err));          }        }, { interval: CommonConstants.SENSOR_INTERVAL });        ... }

位置服务

应用启动后申请位置服务权限,获取权限后启动服务,启动服务后订阅位置服务。通过订阅获取到位置服务数据,解析处理后在页面显示。效果如图所示:

// HomePage.ets requestPermissions(): void {  ...  LocationUtil.geolocationOn((location: geoLocationManager.Location) => {    if (this.latitude === location.latitude && this.longitude === location.longitude) {      return;    }    this.latitude = location.latitude;    this.longitude = location.longitude;    let reverseGeocodeRequest: geoLocationManager.ReverseGeoCodeRequest = {      latitude: this.latitude,      longitude: this.longitude    };    geoLocationManager.getAddressesFromLocation(reverseGeocodeRequest).then(data => {      if (data[0].placeName) {        this.currentLocation = data[0].placeName;      }    }).catch((err: Error) => {      Logger.error(TAG, GetAddressesFromLocation err + JSON.stringify(err));    });  });  ... }

将位置服务相关的函数封装到工具类中。

// LocationUtil.ets class LocationUtil {   geolocationOn( locationChange: ( location: geoLocationManager.Location) => void): void {      let  requestInfo: geoLocationManager. LocationRequest = {       priority: 0x203,       scenario: 0x300,       timeInterval: 0,       distanceInterval: 0,       maxAccuracy: 0    }     try {       geoLocationManager. on( locationChange, requestInfo, locationChange);    } catch (err) {        console. error( "locationChange error:" +  JSON. stringify(err));    }  }   geolocationOff(): void {     geoLocationManager. off( locationChange);  } }

后台任务

点击开始按钮开启后台任务,通过后台任务管理方法配置申请的后台模式等参数启动后台任务。

// HomePage.ets build() {  Stack({ alignContent: Alignment.TopStart }) {    ...    Row() {      Button(this.isStart ? $r(app.string.stop) : $r(app.string.start))        ...        .onClick(() => {          if (this.isStart) {            ...            BackgroundUtil.stopContinuousTask(this.context);          } else {            if (this.stepGoal === || this.currentLocation === ) {              promptAction.showToast({ message: CommonConstants.WAIT });            } else {              ...              BackgroundUtil.startContinuousTask(this.context);            }          }          StepsUtil.putStorageValue(CommonConstants.IS_START, String(this.isStart));        })    }    ... } // BackgroundUtil.ets export class BackgroundUtil {  public static startContinuousTask(context: common.UIAbilityContext): void {    let wantAgentInfo: wantAgent.WantAgentInfo = {      wants: [        {          bundleName: context.abilityInfo.bundleName,          abilityName: context.abilityInfo.name        }      ],      operationType: wantAgent.OperationType.START_ABILITY,      requestCode: 0,      wantAgentFlags: [wantAgent.WantAgentFlags.UPDATE_PRESENT_FLAG]    };    wantAgent.getWantAgent(wantAgentInfo).then((wantAgentObj) => {      try {        backgroundTaskManager.startBackgroundRunning(context,          backgroundTaskManager.BackgroundMode.LOCATION, wantAgentObj).then(() => {          Logger.info(TAG, startBackgroundRunning succeeded);        }).catch((err: Error) => {          Logger.error(TAG, `startBackgroundRunning failed Cause:  ${ JSON.stringify(err)}`);        });      } catch (error) {        Logger.error(TAG, `stopBackgroundRunning failed. error: ${ JSON.stringify(error)} `);      }    });  }  public static stopContinuousTask(context: common.UIAbilityContext): void {    try {      backgroundTaskManager.stopBackgroundRunning(context).then(() => {        Logger.info(TAG, stopBackgroundRunning succeeded);      }).catch((err: Error) => {        Logger.error(TAG, `stopBackgroundRunning failed Cause:  ${ JSON.stringify(err)}`);      });    } catch (error) {      Logger.error(TAG, `stopBackgroundRunning failed. error: ${ JSON.stringify(error)} `);    }  } }

总结

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

1.  计步器传感器的功能实现。

2.  位置服务的功能实现。

3.  后台任务的功能实现。

热点
上一篇:数据中心高温管理指南
下一篇:数据中心网络中的铜缆:是时候向前看了吗?