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

介绍

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

  1. 通过订阅计步器传感器获取计步器数据,处理后显示。
  2. 通过订阅位置服务获取位置数据,处理后显示。
  3. 通过服务开发实现后台任务功能。

相关概念

  • 计步传感器:订阅计步器传感器数据,系统返回相关数据。
  • 后台任务管理:应用中存在用户能够直观感受到的且需要一直在后台运行的业务时(如,后台播放音乐),可以使用长时任务机制。
  • 位置服务:位置服务提供GNSS定位、网络定位、地理编码、逆地理编码、国家码和地理围栏等基本功能。

相关权限

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

● ohos.permission.ACTIVITY_MOTION

● ohos.permission.KEEP_BACKGROUND_RUNNING

● ohos.permission.APPROXIMATELY_LOCATION

● ohos.permission.LOCATION

● ohos.permission.LOCATION_IN_BACKGROUND

环境搭建

安装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
classLocationUtil{
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 classBackgroundUtil{
publicstaticstartContinuousTask(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)} `);
}
});
}

publicstaticstopContinuousTask(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. 后台任务的功能实现。

为了能让大家更好的学习鸿蒙 (Harmony OS) 开发技术,这边特意整理了《鸿蒙 (Harmony OS)开发学习手册》(共计890页),希望对大家有所帮助:https://qr21.cn/FV7h05

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

入门必看:https://qr21.cn/FV7h05

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

HarmonyOS 概念:https://qr21.cn/FV7h05

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

如何快速入门:https://qr21.cn/FV7h05

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

开发基础知识:https://qr21.cn/FV7h05

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

基于ArkTS 开发:https://qr21.cn/FV7h05

  1. Ability开发
  2. UI开发
  3. 公共事件与通知
  4. 窗口管理
  5. 媒体
  6. 安全
  7. 网络与链接
  8. 电话服务
  9. 数据管理
  10. 后台任务(Background Task)管理
  11. 设备管理
  12. 设备使用信息统计
  13. DFX
  14. 国际化开发
  15. 折叠屏系列
  16. ......
相关推荐
AlbertZein8 小时前
ImageKnifePro 源码解读:鸿蒙图片加载框架全貌
harmonyos
AlbertZein9 小时前
鸿蒙工程化:build-profile.json5 逐字段解析
harmonyos
weixin_4171970510 小时前
DeepSeek V4绑定华为:一场飞行中换引擎的国产算力革命
人工智能·华为
前端技术11 小时前
鸿蒙ArkTS 自定义底部导航栏(Tabs+@Builder 极简实现)
harmonyos·鸿蒙
Swift社区12 小时前
为什么“页面跳转”在鸿蒙 PC 上是错误设计?
华为·harmonyos
熬夜敲代码的小N15 小时前
鸿蒙PC开发者必备!GitNext深度测评:一站式Git管理工具
git·华为·harmonyos
秋の本名17 小时前
第一章 鸿蒙生态架构与开发理念
华为·wpf·harmonyos
Ww.xh17 小时前
鸿蒙系统中HTML与Vue集成方案
vue.js·html·harmonyos
前端不太难18 小时前
鸿蒙游戏 CI/CD:为什么你还在手动打包?
游戏·ci/cd·harmonyos
全栈若城18 小时前
HarmonyOS Pen Kit 实战:手写笔轻捏、双击与取色器完整集成
华为·harmonyos·手写笔·harmonyos6