前言

在开发运动类应用时,准确地监听和记录用户的运动步数是一项关键功能。HarmonyOS 提供了强大的传感器框架,使得开发者能够轻松地获取设备的运动数据。本文将深入探讨如何在 HarmonyOS 应用中实现步数监听功能,同时分享一些开发过程中的经验和技巧,帮助你更好地理解和实现这一功能。

1.了解 HarmonyOS 传感器框架

HarmonyOS 提供了多种传感器,其中PEDOMETER(计步器)传感器是用于获取用户运动步数的核心传感器。该传感器返回的是自设备启动后的累计步数,而非增量步数。这意味着我们需要在应用逻辑中处理步数的初始值和增量计算。

2.核心代码实现

2.1 初始化传感器

在开始之前,我们需要申请必要的权限并初始化传感器。以下是初始化传感器的代码:

import { sensor } from '@kit.SensorServiceKit';
import { BusinessError } from '@kit.BasicServicesKit';
import abilityAccessCtrl from '@ohos.abilityAccessCtrl';
import { common } from '@kit.AbilityKit'; export class StepCounterService {
private static instance: StepCounterService;
private stepCount: number = 0; // 当前累计步数
private initialStepCount: number = 0; // 初始步数(设备启动后的累计步数)
private isMonitoring: boolean = false; // 是否正在监听
private isPaused: boolean = false; // 是否暂停
private listeners: Array<(steps: number) => void> = [];
private context: common.UIAbilityContext;
private pausedIntervals: Array<PauseCounter> = [];
private deviceTotalSteps: number = 0; private constructor(context: common.UIAbilityContext) {
this.context = context;
} public static getInstance(context: common.UIAbilityContext): StepCounterService {
if (!StepCounterService.instance) {
StepCounterService.instance = new StepCounterService(context);
}
return StepCounterService.instance;
} private async requestMotionPermission(): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
try {
const result = await atManager.requestPermissionsFromUser(
this.context,
['ohos.permission.ACTIVITY_MOTION']
);
return result.permissions[0] === 'ohos.permission.ACTIVITY_MOTION' &&
result.authResults[0] === 0;
} catch (err) {
console.error('申请权限失败:', err);
return false;
}
} public async startStepCounter(): Promise<void> {
if (this.isMonitoring) return; const hasPermission = await this.requestMotionPermission();
if (!hasPermission) {
throw new Error('未授予运动传感器权限');
} try {
sensor.on(sensor.SensorId.PEDOMETER, (data: sensor.PedometerResponse) => {
this.deviceTotalSteps = data.steps; if (this.initialStepCount === 0) {
this.initialStepCount = data.steps;
} const deltaSteps = this.deviceTotalSteps - this.initialStepCount; if (this.isPaused) {
// 暂停时仅更新设备总步数,不改变业务步数
} else {
// 计算所有暂停区间的总步数
const totalPausedSteps = this.pausedIntervals.reduce((sum, interval) => {
return sum + (interval.end - interval.start);
}, 0); this.stepCount = deltaSteps - totalPausedSteps;
this.notifyListeners();
}
}); this.isMonitoring = true;
} catch (error) {
const e = error as BusinessError;
console.error(`计步器订阅失败: Code=${e.code}, Message=${e.message}`);
throw error as Error;
}
}
}

2.2 暂停和恢复功能

在运动过程中,用户可能需要暂停和恢复运动。为了处理这种情况,我们需要记录暂停和恢复时的步数,并在恢复时计算暂停期间的步数增量。以下是暂停和恢复功能的实现:

public pauseStepCounter(): void {
if (!this.isMonitoring || this.isPaused) return;
this.pausedIntervals.push({
start: this.deviceTotalSteps,
end: 0
});
this.isPaused = true;
} public resumeStepCounter(): void {
if (!this.isMonitoring || !this.isPaused) return; const lastInterval = this.pausedIntervals[this.pausedIntervals.length - 1];
lastInterval.end = this.deviceTotalSteps; this.isPaused = false;
}

2.3 停止监听

当用户完成运动后,我们需要停止监听步数,并清理相关资源:

public stopStepCounter(): void {
if (!this.isMonitoring) return; this.stepCount = 0;
this.initialStepCount = 0;
this.isPaused = false;
this.pausedIntervals = []; // 清空所有暂停记录
try {
sensor.off(sensor.SensorId.PEDOMETER);
this.isMonitoring = false;
} catch (error) {
const e = error as BusinessError;
console.error(`计步器取消订阅失败: Code=${e.code}, Message=${e.message}`);
}
}

3.通知监听器

为了确保界面能够实时更新步数,我们需要在步数变化时通知监听器。为了避免过于频繁的通知,可以使用防抖机制:

private debounceTimer?: number;

private notifyListeners(): void {
if (this.debounceTimer) clearTimeout(this.debounceTimer);
this.debounceTimer = setTimeout(() => {
this.listeners.forEach(listener => listener(this.stepCount));
}, 500); // 每500ms通知一次
}

4.重置步数

在某些情况下,用户可能需要重置步数。以下是重置步数的实现:

public resetStepCounter(): void {
this.initialStepCount = this.deviceTotalSteps;
this.pausedIntervals = [];
this.stepCount = 0;
}

5.使用示例

以下是如何在页面中使用StepCounterService的示例:


@Component
export struct KeepRunningPage {
@State isRunning: boolean = false;
@State stepCount: number = 0; private stepCounterService?: StepCounterService; build() {
Column() {
Text('跑步计步器')
.fontSize(24)
.textAlign(TextAlign.Center)
.margin({ top: 20 }) Text(`步数: ${this.stepCount}`)
.fontSize(18)
.textAlign(TextAlign.Center)
.margin({ top: 20 }) Button('开始跑步')
.onClick(() => this.startRunning())
.margin({ top: 20 }) Button('暂停跑步')
.onClick(() => this.pauseRunning())
.margin({ top: 20 }) Button('恢复跑步')
.onClick(() => this.resumeRunning())
.margin({ top: 20 }) Button('停止跑步')
.onClick(() => this.stopRunning())
.margin({ top: 20 })
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
} aboutToAppear(): void {
this.stepCounterService = StepCounterService.getInstance(Application.getInstance().uiAbilityContext);
this.stepCounterService.addStepListener((steps) => {
this.stepCount = steps;
});
} aboutToDisappear(): void {
this.stepCounterService!.removeStepListener((steps) => {
this.stepCount = steps;
});
} async startRunning(): Promise<void> {
if (!this.isRunning) {
this.isRunning = true;
await this.stepCounterService!.startStepCounter();
}
} pauseRunning(): void {
if (this.isRunning) {
this.stepCounterService!.pauseStepCounter();
}
} resumeRunning(): void {
if (this.isRunning) {
this.stepCounterService!.resumeStepCounter();
}
} stopRunning(): void {
if (this.isRunning) {
this.isRunning = false;
this.stepCounterService!.stopStepCounter();
}
}
}

6.核心点梳理

6.1 权限申请

在使用传感器之前,必须申请ohos.permission.ACTIVITY_MOTION权限。这可以通过abilityAccessCtrl.createAtManager来实现。

6.2 初始步数处理

PEDOMETER传感器返回的是自设备启动后的累计步数。因此,我们需要在第一次获取数据时记录初始步数

6.3 暂停与恢复机制

为了处理用户可能的暂停和恢复操作,我们引入了pausedIntervals数组来记录每次暂停的起始和结束步数。通过这种方式,我们可以在恢复时准确计算出暂停期间的步数增量,并从总步数中扣除这部分步数。

6.4 防抖机制

为了避免频繁通知监听器导致的性能问题,我们在notifyListeners方法中加入了防抖机制。通过设置一个定时器,确保在一定时间间隔(如500ms)内只通知一次监听器,从而减少不必要的更新。

6.5 重置功能

在某些场景下,用户可能需要重置步数计数器。通过resetStepCounter方法,我们可以将初始步数设置为当前设备的总步数,并清空所有暂停记录,从而实现步数的重置。

7.开发中的注意事项

7.1 权限管理

在实际应用中,权限申请是一个不可忽视的环节。如果用户拒绝了权限申请,应用应该友好地提示用户,并提供重新申请权限的选项。

7.2 资源管理

传感器的监听是一个持续的过程,如果不正确管理,可能会导致资源泄漏。因此,在不需要监听时,务必调用sensor.off方法来取消监听。

7.3 数据准确性

由于PEDOMETER传感器返回的是累计步数,因此在处理暂停和恢复时,需要特别注意数据的准确性。确保在暂停和恢复时正确记录和计算步数增量,避免数据偏差。

8.总结

我们详细探讨了如何在 HarmonyOS 应用中实现步数监听功能。从传感器的初始化和权限申请,到暂停、恢复和停止监听的实现。希望这些内容能够帮助你在开发运动类应用时更加得心应手。

HarmonyOS运动开发:如何监听用户运动步数数据的更多相关文章

  1. js中对arry数组的各种操作小结 瀑布流AJAX无刷新加载数据列表--当页面滚动到Id时再继续加载数据 web前端url传递值 js加密解密 HTML中让表单input等文本框为只读不可编辑的方法 js监听用户的键盘敲击事件,兼容各大主流浏览器 HTML特殊字符

    js中对arry数组的各种操作小结   最近工作比较轻松,于是就花时间从头到尾的对js进行了详细的学习和复习,在看书的过程中,发现自己平时在做项目的过程中有很多地方想得不过全面,写的不够合理,所以说啊 ...

  2. Spring Boot实现一个监听用户请求的拦截器

    项目中需要监听用户具体的请求操作,便通过一个拦截器来监听,并继续相应的日志记录 项目构建与Spring Boot,Spring Boot实现一个拦截器很容易. Spring Boot的核心启动类继承W ...

  3. js监听用户的键盘敲击事件,兼容各大主流浏览器

    js监听用户的键盘敲击事件,兼容各大主流浏览器 <script type="text/javascript"> document.onkeydown = functio ...

  4. 监听用户的后退键,解决部分浏览器回退的bug

    监听用户的后退键,解决部分浏览器回退的bug $(document).keydown(function (event) { // 监听backspace键 if (event.keyCode == 8 ...

  5. Android开发之EditText 详解(addTextChangedListener监听用户输入状态)

    为了实现像qq或者微信输入框的效果,当在 EditText输入字符串时发送按钮显示,当输入框字符消除掉时按钮改变.所以这时候我就要用到addTextChangedListener 用它来监听用户输入状 ...

  6. 修改 processor.php 文件,监听用户对该应用的消息

    修改 processor.php 文件,监听用户对该应用的消息 class cgc_fdModuleProcessor extends WeModuleProcessor { public funct ...

  7. iOS 如何监听用户在手机设置里改变了系统的时间?

    如何监听用户未退出APP但通过Home键在手机设置里改变了系统的时间? 用户虽未退出APP,但是当它按Home键退到后台时 ,会调用该方法: - (void)applicationDidEnterBa ...

  8. vue 如何在循环中 "监听" 的绑定v-model数据

    vue 如何在循环中 "监听" 的绑定v-model数据 阅读目录 vue 如何在循环中 "监听" 的绑定v-model数据 1. 普通属性的值进行监听 2. ...

  9. Android开发-之监听button点击事件

    一.实现button点击事件的方法 实现button点击事件的监听方法有很多种,这里总结了常用的四种方法: 1.匿名内部类 2.外部类(独立类) 3.实现OnClickListener接口 4.添加X ...

  10. android开发事件监听

    第一种:匿名内部类作为事件监听器类 大部分时候,事件处理器都没有什么利用价值(可利用代码通常都被抽象成了业务逻辑方法),因此大部分事件监听器只是临时使用一次,所以使用匿名内部类形式的事件监听器更合适, ...

随机推荐

  1. JMeter下载与环境配置

    前置 使用JMeter前需要先配置好Java的环境变量,不会的朋友可以阅读:https://www.cnblogs.com/test-gang/p/18144441 JMeter下载 JMeter官网 ...

  2. RMAN备份时遇到ORA-48132 &ORA-48170且备份变慢案例

    现象描述: 环境: 操作系统:Red Hat Enterprise Linux release 8.10 数据库版本: Oracle 19.24.0.0.0 企业版 备份作业在执行RMAN备份时,告警 ...

  3. flutter-全局监听路由

    main.dart navigatorObservers: [ MyApp.routeObserver, GLObserver(),//全局监听路由 ], router_listener.dart c ...

  4. 用 DeepSeek 给对象做个网站,她一定感动坏了

    大家好,我是程序员鱼皮.又是一年特殊的日子,作为一名程序员,总是幻想着自己有对象, 总是想着用自己贼拉牛 X 的编程技术给对象做个网站. 本文对应视频,观看体验更好哦:https://bilibili ...

  5. C语言程序设计手写笔记

    最近自己录了一个自学C语言系列,笔记发出来,视频还在传

  6. Docker Hub 无法访问,替代镜像

    我使用以下配置成功拉取了mysql 8.0.33 和redis lastest,但是不知道究竟是哪一个起作用了 linux 执行 sudo vim /etc/docker/daemon.json 填入 ...

  7. 震撼揭秘:LLM幻觉如何颠覆你的认知!

    LLM幻觉 把幻觉理解为训练流水线中的一种涌现认知效应 Prashal Ruchiranga Robina Weermeijer 在 Unsplash 上的照片 介绍 在一个名为<深入剖析像Ch ...

  8. surpac 中如何删除点

    找到显示的编号 输入线窜线段编号

  9. 多机器的键鼠互通——Synergy/Deskflow配置记录

    Synergy (1.14.6) 情况一样,那么感觉就是机器之间TCP连接有问题,测试不同 一些测试命令 ss -tlnp | grep 24800 # 查看端口情况 sudo lsof -i :24 ...

  10. 利用队列的内置模块(deque)模拟 Linux 下的 tail 命令(输出文件中最后几行的内容)

    博客地址:https://www.cnblogs.com/zylyehuo/ # -*- coding: utf-8 -*- from collections import deque def tai ...