

一、引言
传感器是智能设备感知物理世界的重要组件。通过加速度计、陀螺仪、磁力计、光线传感器等,应用可以感知设备的运动状态、方向和环境变化,从而实现计步、横竖屏切换、游戏控制、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 是传感器监听的核心:
-
防重入 :
if (this.listening) return防止重复开启监听。 -
设置状态 :
this.listening = true标记监听中。 -
开启监听 :
sensor.on注册加速度计监听:- 回调中实时更新三轴数据。
data.x.toFixed(2)保留两位小数。- 更新
rows表格数据,由于是@State,UI 自动刷新。 interval: 100000000表示每 100 毫秒上报一次,适合 UI 展示。
-
异常处理:传感器可能不可用(如模拟器),捕获异常并提示。
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')
代码说明:
环形仪表盘是页面的视觉核心:
-
外环背景 :200x200 的深蓝色圆环(#1A5A8A),
strokeWidth(16)粗描边。 -
外环进度 :青色圆环(#00D2FF),通过
strokeDashArray([100, 100])模拟半圆进度效果,rotate({ angle: -90 })旋转到顶部起始。 -
内环:160x160 的深色圆盘,作为仪表盘内衬。
-
数据展示:仪表盘中心显示综合强度:
- 综合强度通过勾股定理计算:
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 传感器开发,通过一个深蓝仪表盘风格的演示页面实战演示了加速度计监听、数据展示和开关控制等核心能力。
核心要点回顾:
sensor.on开启监听,sensor.off关闭监听。- 传感器数据通过回调实时获取。
interval控制上报频率(纳秒)。- 加速度计返回三轴加速度数据。
- 页面销毁时必须关闭监听,避免资源泄漏。
- 综合强度通过勾股定理计算。
- 使用前检查传感器可用性。
传感器让应用能感知物理世界,掌握它能构建计步、游戏控制、AR 等丰富功能。下一篇我们将讲解 HarmonyOS 手势交互。