2、Android传感器框架:SensorManager、Sensor、SensorEvent 三大核心类介绍
好,咱们正式开始接触Android传感器的核心代码层。
上一章我们聊了陀螺仪能干什么,这一章,我们来拆解一下Android到底是怎么让你拿到传感器数据的。说白了,就是三个类:SensorManager、Sensor、SensorEvent。
我刚开始接触Android传感器时,也被这三个类绕得有点晕。后来发现,其实它们的关系特别简单——一个管注册,一个管描述,一个管数据。你只要记住这个口诀,后面就顺了。
核心口诀:
- SensorManager —— 传感器管理员,负责获取传感器列表、注册/注销监听器。
- Sensor —— 传感器本身的信息卡,告诉你这个传感器叫什么、什么类型、精度如何。
- SensorEvent —— 传感器的一次数据快照,包含时间戳、数值数组、精度等。
2.1 SensorManager —— 传感器的“大管家”
SensorManager 是你和传感器硬件之间的桥梁。你想想看,手机里那么多传感器——陀螺仪、加速度计、磁力计、光线传感器……总得有个统一的管理入口吧?SensorManager 就是干这个的。
获取它的方式很简单:
SensorManager sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
嗯,这里要注意:SensorManager 是一个系统服务,你不需要自己去 new 它。Android 系统在开机时就已经初始化好了。
我个人习惯在 Activity 的 onCreate() 里获取 SensorManager,然后在 onResume() 里注册监听器,onPause() 里注销。为什么?因为传感器很耗电,你不看它的时候就应该关掉。
避坑指南:
我曾经在项目中犯过一个低级错误——在 onCreate() 里注册了监听器,但忘了在 onPause() 里注销。结果用户切到后台后,陀螺仪还在疯狂上报数据,电量哗哗地掉。后来被测试小姐姐追着骂了一周……
所以记住:注册和注销一定要成对出现。
2.2 Sensor —— 传感器的“身份证”
Sensor 对象本身不包含实时数据,它只描述传感器本身的属性。你可以把它理解成传感器的“身份证”。
常用的方法有这些:
| 方法 | 返回值 | 说明 |
|---|---|---|
getName() |
String | 传感器名称,比如 "MPU-6500" |
getType() |
int | 传感器类型常量,陀螺仪是 Sensor.TYPE_GYROSCOPE |
getResolution() |
float | 传感器分辨率,单位取决于传感器类型 |
getMaximumRange() |
float | 传感器最大量程 |
getPower() |
float | 传感器功耗,单位 mA |
getVendor() |
String | 传感器供应商,比如 "InvenSense" |
获取陀螺仪 Sensor 对象的方式:
Sensor gyroscope = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
if (gyroscope == null) {
// 你的手机没有陀螺仪!这种情况在低端机上偶尔会遇到
}
为什么用 getDefaultSensor() 而不是 getSensorList()?因为大多数情况下,系统会给你返回一个“最合适”的传感器。如果手机上有多个同类型传感器(比如一个高精度但费电,一个低精度但省电),系统会帮你选一个默认的。
注意:
不是所有手机都有陀螺仪!我测试过一款百元机,getDefaultSensor(Sensor.TYPE_GYROSCOPE) 返回了 null。所以一定要做空值判断,否则你的 App 会在那些手机上直接崩溃。
2.3 SensorEvent —— 传感器的“数据快照”
终于到了最核心的部分——拿到数据。
当传感器有新的数据时,系统会回调 onSensorChanged(SensorEvent event) 方法。这个 event 对象里包含了所有你需要的信息。
SensorEvent 的主要成员:
| 成员 | 类型 | 说明 |
|---|---|---|
values |
float[] | 传感器数据数组,陀螺仪是 3 个值:x、y、z 轴角速度 |
sensor |
Sensor | 触发该事件的 Sensor 对象 |
accuracy |
int | 精度等级:0=不可靠,1=低,2=中,3=高 |
timestamp |
long | 事件发生的时间戳,单位纳秒 |
陀螺仪的 values[] 数组含义:
values[0]—— 绕 X 轴的角速度(单位:rad/s),也就是手机的横滚(Roll)values[1]—— 绕 Y 轴的角速度(单位:rad/s),也就是手机的俯仰(Pitch)values[2]—— 绕 Z 轴的角速度(单位:rad/s),也就是手机的偏航(Yaw)
一个完整的监听器实现:
private SensorEventListener gyroListener = new SensorEventListener() {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
float x = event.values[0];
float y = event.values[1];
float z = event.values[2];
// 这里就可以用 x、y、z 做你想做的事了
// 比如计算旋转角度、检测手机是否被拿起等等
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// 精度变化时回调,一般不需要处理
// 但如果 accuracy 突然变成 0,说明传感器出问题了
}
};
关键点:
陀螺仪返回的是角速度,不是角度。如果你想得到手机旋转了多少度,需要对角速度做积分。这个我们后面会详细讲,现在先记住:values[] 的单位是 弧度/秒 (rad/s)。
2.4 注册与注销 —— 生命周期管理
有了上面三个类,最后一步就是把它们串起来。注册监听器的标准写法:
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(
gyroListener, // 监听器
gyroscope, // 传感器对象
SensorManager.SENSOR_DELAY_NORMAL // 采样频率
);
}
@Override
protected void onPause() {
super.onPause();
sensorManager.unregisterListener(gyroListener);
}
采样频率有四个可选值:
| 常量 | 说明 | 典型延迟 |
|---|---|---|
SENSOR_DELAY_NORMAL |
普通游戏或屏幕旋转 | 约 200ms |
SENSOR_DELAY_UI |
UI 更新场景 | 约 60ms |
SENSOR_DELAY_GAME |
游戏场景 | 约 20ms |
SENSOR_DELAY_FASTEST |
最快频率,不限制 | 取决于硬件 |
我的建议:
不要一上来就用 FASTEST。我曾经为了追求“实时性”把采样率设成最快,结果手机烫得能煎鸡蛋。后来发现,对于大多数场景,GAME 甚至 NORMAL 就完全够用了。省电又凉快,何乐而不为?
2.5 小结
好了,这一章的核心内容就这些。总结一下:
- SensorManager 负责获取传感器和注册监听器
- Sensor 描述传感器的元信息,不包含实时数据
- SensorEvent 是数据载体,
values[]里存着陀螺仪的 x、y、z 角速度 - 记得在
onPause()里注销监听器,别让电量偷偷溜走
下一章我们会真正动手写代码,让陀螺仪的数据在屏幕上动起来。不过在那之前,建议你把这三个类的 API 文档翻一翻,尤其是 SensorEvent 的 timestamp 字段——它在后面做数据融合时会非常有用。
公众号:蓝海资料掘金营,微信deep3321