ArkTS传感器开发:加速度计与数据监听

一、引言

传感器是智能设备感知物理世界的重要组件。通过加速度计、陀螺仪、磁力计、光线传感器等,应用可以感知设备的运动状态、方向和环境变化,从而实现计步、横竖屏切换、游戏控制、AR 体验等功能。

HarmonyOS 提供了完整的传感器框架(@kit.SensorServiceKit),支持多种传感器类型和数据监听。本文将以一个深蓝仪表盘风格的传感器演示页面为主线,深入讲解传感器开发的核心技能。

二、传感器体系概览

2.1 传感器类型

HarmonyOS 支持多种传感器:

传感器 SensorId 用途
加速度计 ACCELEROMETER 检测设备加速度
陀螺仪 GYROSCOPE 检测角速度
磁力计 MAGNETOMETER 检测磁场方向
光线传感器 AMBIENT_LIGHT 检测环境光强度
距离传感器 PROXIMITY 检测物体距离
气压计 BAROMETER 检测大气压强
心率传感器 HEART_RATE 检测心率
计步器 PEDOMETER 检测步数

2.2 传感器数据模型

每种传感器返回不同的数据结构:

typescript 复制代码
// 加速度计数据
interface AccelerometerResponse {
  x: number;  // X 轴加速度 (m/s²)
  y: number;  // Y 轴加速度
  z: number;  // Z 轴加速度
}

// 陀螺仪数据
interface GyroscopeResponse {
  x: number;  // X 轴角速度 (rad/s)
  y: number;
  z: number;
}

// 光线传感器数据
interface LightResponse {
  intensity: number;  // 光照强度 (lux)
}

三、传感器核心 API

3.1 开启监听

typescript 复制代码
import { sensor } from '@kit.SensorServiceKit';

// 开启加速度计监听
sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {
  console.info(`X: ${data.x}, Y: ${data.y}, Z: ${data.z}`);
}, { interval: 100000000 });

代码说明:

  • sensor.on(sensorId, callback, options) 开启传感器监听。
  • 第一个参数:传感器类型。
  • 第二个参数:数据回调,传感器产生数据时触发。
  • 第三个参数:监听选项,interval 是数据上报间隔(纳秒)。

3.2 关闭监听

typescript 复制代码
// 关闭加速度计监听
sensor.off(sensor.SensorId.ACCELEROMETER);

3.3 单次获取

typescript 复制代码
// 单次获取传感器数据
const data = sensor.getSingleSensorData(sensor.SensorId.ACCELEROMETER);
console.info(`X: ${data.x}, Y: ${data.y}, Z: ${data.z}`);

3.4 监听间隔

interval 参数控制数据上报频率,单位是纳秒:

typescript 复制代码
// 100 毫秒上报一次(适合 UI 展示)
{ interval: 100000000 }

// 20 毫秒上报一次(适合游戏)
{ interval: 20000000 }

// 1 秒上报一次(适合低频监控)
{ interval: 1000000000 }

四、实战代码:传感器仪表盘页面

下面我们实现一个深蓝仪表盘风格的传感器演示页面,包含环形仪表盘、开关控制和实时数据表格。

4.1 定义数据结构

typescript 复制代码
interface SensorRow {
  name: string;
  value: string;
  unit: string;
}

代码说明:

SensorRow 接口描述传感器数据表格中的一行数据,包含传感器名称、数值和单位。

4.2 组件状态定义

typescript 复制代码
@Entry
@Component
struct SensorPage {
  @State accelX: number = 0;
  @State accelY: number = 0;
  @State accelZ: number = 0;
  @State listening: boolean = false;
  @State rows: SensorRow[] = [
    { name: '加速度 X', value: '0.00', unit: 'm/s²' },
    { name: '加速度 Y', value: '0.00', unit: 'm/s²' },
    { name: '加速度 Z', value: '0.00', unit: 'm/s²' }
  ];

代码说明:

  • @State accelX/Y/Z:三轴加速度值。
  • @State listening:监听状态标志。
  • @State rows:实时数据表格。

4.3 开启监听

typescript 复制代码
startListening(): void {
  if (this.listening) {
    return;
  }
  this.listening = true;
  try {
    sensor.on(sensor.SensorId.ACCELEROMETER, (data: sensor.AccelerometerResponse) => {
      this.accelX = data.x;
      this.accelY = data.y;
      this.accelZ = data.z;
      this.rows = [
        { name: '加速度 X', value: data.x.toFixed(2), unit: 'm/s²' },
        { name: '加速度 Y', value: data.y.toFixed(2), unit: 'm/s²' },
        { name: '加速度 Z', value: data.z.toFixed(2), unit: 'm/s²' }
      ];
    }, { interval: 100000000 });
    promptAction.showToast({ message: '传感器监听已开启' });
  } catch (e) {
    this.listening = false;
    promptAction.showToast({ message: `开启失败: ${JSON.stringify(e)}` });
  }
}

代码说明:

startListening 是传感器监听的核心:

  1. 防重入if (this.listening) return 防止重复开启监听。

  2. 设置状态this.listening = true 标记监听中。

  3. 开启监听sensor.on 注册加速度计监听:

    • 回调中实时更新三轴数据。
    • data.x.toFixed(2) 保留两位小数。
    • 更新 rows 表格数据,由于是 @State,UI 自动刷新。
    • interval: 100000000 表示每 100 毫秒上报一次,适合 UI 展示。
  4. 异常处理:传感器可能不可用(如模拟器),捕获异常并提示。

4.4 关闭监听

typescript 复制代码
stopListening(): void {
  if (!this.listening) {
    return;
  }
  try {
    sensor.off(sensor.SensorId.ACCELEROMETER);
    this.listening = false;
    promptAction.showToast({ message: '传感器监听已关闭' });
  } catch (e) {
    promptAction.showToast({ message: `关闭失败: ${JSON.stringify(e)}` });
  }
}

代码说明:

  • sensor.off(sensor.SensorId.ACCELEROMETER) 关闭监听。
  • 更新监听状态标志。
  • 关闭后传感器不再上报数据。

4.5 页面销毁时清理

typescript 复制代码
aboutToDisappear(): void {
  if (this.listening) {
    sensor.off(sensor.SensorId.ACCELEROMETER);
  }
}

代码说明:

  • 在组件销毁时(页面退出)自动关闭监听,避免资源泄漏。
  • 这是传感器开发的重要实践:离开页面必须关闭监听

4.6 构建 UI

typescript 复制代码
build() {
  Scroll() {
    Column({ space: 16 }) {
      // 顶部标题
      Column() {
        Text('SENSOR')
          .fontSize(12)
          .fontColor('#99E6FF')
          .letterSpacing(6)
        Text('传感器')
          .fontSize(26)
          .fontWeight(FontWeight.Bold)
          .fontColor(Color.White)
          .margin({ top: 6 })
        Text('加速度计 · 实时数据流')
          .fontSize(12)
          .fontColor('#99E6FF')
          .margin({ top: 6 })
      }
      .width('100%')
      .padding({ top: 48, bottom: 30 })
      .backgroundColor('#0B3D6B')

      // 环形仪表盘
      Stack({ alignContent: Alignment.Center }) {
        // 外环背景
        Circle({ width: 200, height: 200 })
          .fill('none')
          .stroke('#1A5A8A')
          .strokeWidth(16)
        // 外环进度(模拟综合强度)
        Circle({ width: 200, height: 200 })
          .fill('none')
          .stroke('#00D2FF')
          .strokeWidth(16)
          .strokeDashArray([100, 100])
          .rotate({ angle: -90 })
        // 内环
        Circle({ width: 160, height: 160 })
          .fill('#0E4A7A')
        Column({ space: 4 }) {
          Text('综合强度')
            .fontSize(12)
            .fontColor('#99E6FF')
          Text(`${Math.sqrt(this.accelX * this.accelX + this.accelY * this.accelY + this.accelZ * this.accelZ).toFixed(1)}`)
            .fontSize(34)
            .fontWeight(FontWeight.Bold)
            .fontColor('#00D2FF')
          Text(this.listening ? '监听中' : '未监听')
            .fontSize(11)
            .fontColor(this.listening ? '#2ED573' : '#FF6B81')
        }
      }
      .width('100%')
      .height(240)
      .backgroundColor('#0B3D6B')

代码说明:

环形仪表盘是页面的视觉核心:

  1. 外环背景 :200x200 的深蓝色圆环(#1A5A8A),strokeWidth(16) 粗描边。

  2. 外环进度 :青色圆环(#00D2FF),通过 strokeDashArray([100, 100]) 模拟半圆进度效果,rotate({ angle: -90 }) 旋转到顶部起始。

  3. 内环:160x160 的深色圆盘,作为仪表盘内衬。

  4. 数据展示:仪表盘中心显示综合强度:

    • 综合强度通过勾股定理计算:sqrt(x² + y² + z²)
    • 大号青色数字显示强度值。
    • 监听状态用绿色(监听中)或红色(未监听)显示。
typescript 复制代码
      // 开关按钮
      Toggle({ type: ToggleType.Switch, isOn: this.listening })
        .selectedColor('#00D2FF')
        .switchPointColor(Color.White)
        .onChange((isOn: boolean) => {
          if (isOn) {
            this.startListening();
          } else {
            this.stopListening();
          }
        })

      Text(this.listening ? '滑动开关关闭可停止监听' : '滑动开关开启传感器监听')
        .fontSize(12)
        .fontColor('#7FB3D5')

代码说明:

开关控制使用 Toggle 组件:

  • Toggle({ type: ToggleType.Switch, isOn: this.listening }) 创建开关,isOn 绑定监听状态。
  • .selectedColor('#00D2FF') 开关开启时的颜色。
  • .onChange 回调:开启时调用 startListening,关闭时调用 stopListening
typescript 复制代码
      // 传感器数据表格
      Column() {
        Text('实时数据')
          .fontSize(14)
          .fontWeight(FontWeight.Bold)
          .fontColor('#00D2FF')
          .alignSelf(ItemAlign.Start)
          .margin({ bottom: 8 })
        ForEach(this.rows, (row: SensorRow) => {
          Row({ space: 12 }) {
            Text(row.name)
              .fontSize(13)
              .fontColor('#E0F0FF')
              .layoutWeight(1)
            Text(`${row.value} ${row.unit}`)
              .fontSize(13)
              .fontWeight(FontWeight.Bold)
              .fontColor('#00D2FF')
              .fontFamily('monospace')
          }
          .width('100%')
          .padding({ top: 12, bottom: 12 })
          .border({ width: { bottom: 1 }, color: '#1A5A8A' })
        })
      }
      .width('100%')
      .padding(16)
      .backgroundColor('#0E4A7A')
      .borderRadius(14)
      .border({ width: 1, color: '#1A5A8A' })

代码说明:

实时数据表格展示三轴加速度数据:

  • 每行左侧是传感器名称(浅色文字),右侧是数值(青色等宽字体)。
  • 数据随传感器回调实时更新。
  • 行间用深蓝色边框分隔,融入深蓝仪表盘风格。

五、其他传感器实战

5.1 陀螺仪

typescript 复制代码
// 开启陀螺仪监听
sensor.on(sensor.SensorId.GYROSCOPE, (data: sensor.GyroscopeResponse) => {
  console.info(`角速度 X: ${data.x}, Y: ${data.y}, Z: ${data.z}`);
}, { interval: 100000000 });

5.2 光线传感器

typescript 复制代码
// 开启光线传感器监听
sensor.on(sensor.SensorId.AMBIENT_LIGHT, (data: sensor.LightResponse) => {
  console.info(`光照强度: ${data.intensity} lux`);
}, { interval: 100000000 });

5.3 计步器

typescript 复制代码
// 开启计步器监听
sensor.on(sensor.SensorId.PEDOMETER, (data: sensor.PedometerResponse) => {
  console.info(`步数: ${data.steps}`);
}, { interval: 100000000 });

5.4 距离传感器

typescript 复制代码
// 开启距离传感器监听(用于通话时熄屏)
sensor.on(sensor.SensorId.PROXIMITY, (data: sensor.ProximityResponse) => {
  console.info(`距离: ${data.distance} cm`);
}, { interval: 100000000 });

六、传感器最佳实践

6.1 资源管理

传感器监听会持续消耗资源,务必在不需要时关闭监听,在页面销毁时清理。

6.2 合理设置间隔

  • UI 展示:100ms 间隔足够。
  • 游戏/AR:需要更高频率。
  • 低频监控:1 秒以上间隔。

6.3 传感器可用性检查

部分设备可能缺少某些传感器,使用前应检查:

typescript 复制代码
// 检查传感器是否存在
const isSupport = sensor.isSupportSensor(sensor.SensorId.ACCELEROMETER);
if (!isSupport) {
  console.info('设备不支持加速度计');
}

6.4 数据平滑处理

传感器数据有噪声,可进行平滑处理:

typescript 复制代码
// 简单移动平均
let history: number[] = [];
function smooth(value: number): number {
  history.push(value);
  if (history.length > 5) {
    history.shift();
  }
  return history.reduce((a, b) => a + b, 0) / history.length;
}

七、常见问题

7.1 模拟器无传感器数据

原因:模拟器通常不支持真实传感器。

解决:在真机测试,或使用模拟数据。

7.2 监听不生效

原因:传感器不可用、间隔设置过小、或未正确注册。

解决 :检查传感器支持情况,确认 sensor.on 参数正确。

7.3 资源泄漏

原因:开启监听后未关闭。

解决 :在 aboutToDisappear 中关闭监听。

八、总结

本文深入讲解了 HarmonyOS 传感器开发,通过一个深蓝仪表盘风格的演示页面实战演示了加速度计监听、数据展示和开关控制等核心能力。

核心要点回顾:

  1. sensor.on 开启监听,sensor.off 关闭监听。
  2. 传感器数据通过回调实时获取。
  3. interval 控制上报频率(纳秒)。
  4. 加速度计返回三轴加速度数据。
  5. 页面销毁时必须关闭监听,避免资源泄漏。
  6. 综合强度通过勾股定理计算。
  7. 使用前检查传感器可用性。

传感器让应用能感知物理世界,掌握它能构建计步、游戏控制、AR 等丰富功能。下一篇我们将讲解 HarmonyOS 手势交互。

相关推荐
存在morning39 分钟前
【PySpark 学习笔记 六】性能优化:分区、Shuffle、缓存与数据倾斜
笔记·学习·性能优化
我爱cope1 小时前
【计算机网络 | 网络层6:IPv4 数据报格式:TTL、分片、首部校验和分别有什么用?】
网络·学习·计算机网络
math_hongfan1 小时前
鸿蒙 ArkTS 国际化:多语言支持与资源管理
学习·华为·harmonyos·鸿蒙
~kiss~1 小时前
Memory Agent System 之 主动式记忆体 Proactive Memory
学习
超爱西西鸭1 小时前
基于HarmonyOS的表单与校验:输入验证与正则表达式
学习·华为·harmonyos·鸿蒙
蓝速科技1 小时前
蓝速科技丨鸿蒙跨芯片兼容方案:破解信创硬件碎片化落地难题
科技·华为·harmonyos
MartinYeung53 小时前
[论文学习]PoisonBench:评估语言模型对投毒偏好数据的脆弱性
人工智能·学习·语言模型
xian_wwq11 小时前
【学习笔记】-深度认知系列-第1讲-AI不是魔法——三句话讲清楚人工智能到底是什么
笔记·学习·深度认知
M78佐菲11 小时前
c语言学习笔记:排序与查找方法整理
linux·c语言·笔记·学习·算法