Sensors API — 是Android平台用于访问设备硬件传感器的接口。API提供了从加速度计、陀螺仪、磁力计、光传感器和其他传感器获取数据的统一方式。根据Google,2026的数据,超过95%的现代Android设备至少配备三种类型的传感器,这为开发上下文感知应用程序开辟了广阔的可能性。
要点
Sensors API — 是Android Framework的编程接口,为开发者提供对移动设备硬件传感器的访问。API自1.0版本起就是Android SDK的一部分,可通过android.hardware包访问。该接口抽象了不同制造商(Qualcomm、MediaTek、Samsung Exynos)传感器实现之间的差异,并提供统一的传感器工作模型。
API允许执行三个关键操作:获取可用传感器列表、注册监听器以接收数据以及管理读取更新频率。SensorManager是所有操作的中心访问点。系统通过onSensorChanged回调通知应用程序,传递包含float值数组的SensorEvent对象。
在Android存在期间,API经历了几个发展阶段。2.3(Gingerbread)版本中引入了Batch Processing支持——将传感器事件分组以降低能耗。Android 4.0(Ice Cream Sandwich)添加了Gravity和Linear Acceleration虚拟传感器。从Android 8.0开始,系统限制了对传感器的后台访问以提高隐私性。
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
val sensorList: List<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)
sensorList.forEach { sensor ->
Log.d("传感器", "${sensor.name} — ${sensor.type}")
}
并非所有设备都有相同的传感器集。应用程序在注册监听器之前必须检查特定传感器的可用性。Android模拟器仅支持有限的传感器集——加速度计和磁力计。测试其他传感器需要物理设备。从Android 12开始,应用程序必须在清单中声明传感器使用。
Android将所有传感器分为三类:Motion(运动)、Position(位置)和Environment(环境)。Motion传感器包括加速度计、陀螺仪和计步器。Position传感器包括磁力计和Orientation。Environment——光传感器、压力、温度和湿度传感器。
| 类别 | 传感器 | 类型(常量) | 物理/虚拟 |
|---|---|---|---|
| Motion | 加速度计 | TYPE_ACCELEROMETER | 物理 |
| Motion | 陀螺仪 | TYPE_GYROSCOPE | 物理 |
| Motion | 计步器 | TYPE_STEP_COUNTER | 物理 |
| Motion | Gravity | TYPE_GRAVITY | 虚拟 |
| Position | 磁力计 | TYPE_MAGNETIC_FIELD | 物理 |
| Position | Rotation Vector | TYPE_ROTATION_VECTOR | 虚拟 |
| Environment | 光 | TYPE_LIGHT | 物理 |
| Environment | 压力 | TYPE_PRESSURE | 物理 |
加速度计沿三个轴(X、Y和Z)测量以m/s²为单位的加速度。数值包括重力(静止状态下Z轴为9.8 m/s²)。陀螺仪测量以rad/s为单位的角速度——设备绕每个轴的旋转速度。这两种传感器的组合用于导航、游戏和AR应用。
class SensorActivity : Activity(), SensorEventListener {
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_ACCELEROMETER) {
val x = event.values[0]
val y = event.values[1]
val z = event.values[2]
textView.text = "X: $x, Y: $y, Z: $z"
}
}
override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) {}
}
磁力计(TYPE_MAGNETIC_FIELD)沿三个轴测量以微特斯拉(µT)为单位的磁场。用作数字指南针——与加速度计结合使用可以确定设备的方位角。Rotation Vector——一种虚拟传感器,结合陀螺仪、加速度计和磁力计的数据以精确确定方向。
光传感器(TYPE_LIGHT)测量以勒克斯(lx)为单位的外部光照水平。用于自动调节屏幕亮度。压力传感器(TYPE_PRESSURE)测量以百帕(hPa)为单位的大气压力——在导航应用中用于确定海拔高度。
Sensors API构建在客户端-服务器架构上。应用程序充当客户端,SensorManager充当Android系统服务。当应用程序通过registerListener注册监听器时,SensorManager连接到HAL(硬件抽象层)——在Linux内核级别运行的低级传感器驱动程序。
HAL驱动程序从硬件芯片接收原始数据,过滤噪声,并通过SensorService(系统进程)将数据向上传递到应用程序。数据作为SensorEvent对象传输,包含float值数组values和以纳秒为单位的时间戳。事件频率取决于所选的传递模式。
注册监听器时,开发者通过SENSOR_DELAY_NORMAL(200 ms)、SENSOR_DELAY_UI(60 ms)、SENSOR_DELAY_GAME(20 ms)和SENSOR_DELAY_FASTEST(0 ms——最大频率)常量指定事件之间所需的延迟。实际频率可能有所不同——系统优化能耗。
val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
sensorManager.registerListener(
this,
sensor,
SensorManager.SENSOR_DELAY_GAME
)
从Android 2.3开始,传感器支持批处理模式——事件在FIFO缓冲区中累积并一次性传递。这允许处理器更长时间保持在睡眠模式,将能耗降低高达60%。缓冲区大小取决于传感器芯片,在Sensor.fifoMaxEventCount字段中指定。
SensorManager — 可通过getSystemService(Context.SENSOR_SERVICE)访问的系统服务。提供获取传感器列表、获取特定默认传感器以及注册/取消监听器的方法。SensorManager——单例,整个应用程序只有一个实例。
在使用传感器之前,必须检查其是否存在。getDefaultSensor(type)方法在设备上不存在传感器时返回null。获取null而不进行检查将在注册监听器时导致NullPointerException。所有传感器的列表由getSensorList(type)方法返回。
fun checkSensorAvailability(type: Int): Boolean {
val sensorManager =
getSystemService(Context.SENSOR_SERVICE) as SensorManager
return sensorManager.getDefaultSensor(type) != null
}
// 使用:
if (checkSensorAvailability(Sensor.TYPE_GYROSCOPE)) {
Log.d("Sensor", "陀螺仪可用")
}
监听器通过registerListener(listener, sensor, delay)注册。重要:必须在onPause()方法中通过unregisterListener(listener)取消监听器。如果不这样做,应用程序将继续接收传感器事件,即使在后台也会消耗电池。Android 8+在logcat中显示关于未注册监听器的警告。
onAccuracyChanged(sensor, accuracy)方法在传感器精度变化时被调用。值:SENSOR_STATUS_ACCURACY_HIGH、MEDIUM、LOW和UNRELIABLE。接收到UNRELIABLE时,应忽略传感器数据直到精度恢复。例如,磁力计需要校准——以8字形摇晃设备。
让我们看看Kotlin Android应用中使用Sensors API的实际示例。第一个示例——使用加速度计确定屏幕方向。第二个——带有校准的磁力计读数。第三个——使用计步器的步数检测器。
使用加速度计和磁力计的组合来确定方向。SensorManager.getRotationMatrix()方法计算旋转矩阵,getOrientation()提取pitch、roll和azimuth角度。Azimuth(方位角)——相对于磁北的角度,以弧度为单位。
val gravity = FloatArray(3)
val geomagnetic = FloatArray(3)
val rotationMatrix = FloatArray(9)
val orientation = FloatArray(3)
SensorManager.getRotationMatrix(
rotationMatrix, null, gravity, geomagnetic
)
SensorManager.getOrientation(rotationMatrix, orientation)
// orientation[0] — azimuth, [1] — pitch, [2] — roll
val azimuthDeg = Math.toDegrees(orientation[0].toDouble())
计步器(TYPE_STEP_COUNTER)返回自设备上次重启以来用户走过的总步数。传感器在硬件级别工作——即使应用程序未运行也处于活动状态。要获取会话期间的步数,需要保存初始值并计算差值。
var initialSteps = 0
var isInitialized = false
override fun onSensorChanged(event: SensorEvent) {
if (event.sensor.type == Sensor.TYPE_STEP_COUNTER) {
if (!isInitialized) {
initialSteps = event.values[0].toInt()
isInitialized = true
}
val currentSteps = event.values[0].toInt()
val sessionSteps = currentSteps - initialSteps
Log.d("步数", "会话步数:$sessionSteps")
}
}
光传感器允许根据环境条件调整界面。在低光照(低于10 lx)下可以切换到深色主题。在强阳光下(超过10000 lx)——可以增加对比度。去噪使用最后5个值的移动平均值。
Android提供了几个没有直接硬件对应物的虚拟传感器。虚拟传感器基于物理传感器的组合计算其读数。这减轻了开发者的负担——系统自行实现数据融合算法。
Gravity(TYPE_GRAVITY)传感器使用低通滤波器从加速度计读数中提取重力分量。Linear Acceleration(TYPE_LINEAR_ACCELERATION)——反过来,去除重力并仅保留设备的线性加速度。Gravity和Linear Acceleration之和给出加速度计的原始读数。
Rotation Vector——最复杂的虚拟传感器。它结合了陀螺仪(高频变化)、加速度计(重力向量)和磁力计(相对于北方的方向)的数据。结果——描述设备在空间中绝对方向的四元数。用于AR应用和VR头显。
Game Rotation Vector——不使用磁力计的Rotation Vector简化版本。这提供了较低的方位角精度,但更高的更新频率和稳定性。推荐用于低延迟重要的游戏,而非相对于北方的绝对方向。
传感器——设备中最耗能的组件之一。加速度计和陀螺仪在最大轮询频率下可以在3-4小时连续使用中耗尽电池。优化传感器工作是使用Sensors API的任何应用的关键任务。
不要在没有必要的情况下使用SENSOR_DELAY_FASTEST。对于UI动画,SENSOR_DELAY_UI(60 ms)就足够了。对于屏幕方向确定——SENSOR_DELAY_NORMAL(200 ms)。频率越高,处理器在活动状态下的时间就越多。NORMAL和FASTEST之间的能耗差异高达10倍。
从Android 8.0(API 26)开始,后台应用程序接收传感器事件的频率降低。在Android 12+中,后台访问Motion和Position传感器需要BODY_SENSORS_BACKGROUND权限。在应用程序进入后台模式时取消监听器注册——这可以延长设备的电池寿命。
通过registerListener(listener, sensor, delay, maxReportLatencyUs)方法使用批处理。maxReportLatencyUs参数指定事件传递的最大延迟(以微秒为单位)。当值为1000000(1秒)时,事件在传感器的FIFO缓冲区中累积并每秒传递一次——处理器更少地从睡眠中唤醒。
常见问题
最小集——加速度计和磁力计。这两个传感器存在于超过95%的设备上。陀螺仪、光传感器和接近传感器——在现代型号的70-80%上。其他传感器(压力、温度、湿度、计步器)较不常见,取决于设备的价位。
TYPE_ACCELEROMETER返回包括重力在内的完整加速度(9.8 m/s²)。TYPE_LINEAR_ACCELERATION返回不含重力的加速度——仅来自设备运动的加速度。如果设备静止不动,加速度计将在Z轴上显示9.8 m/s²,而Linear Acceleration在所有轴上显示0。
使用getPackageManager().hasSystemFeature()配合相应的常量:FEATURE_SENSOR_ACCELEROMETER、FEATURE_SENSOR_GYROSCOPE、FEATURE_SENSOR_PROXIMITY等。替代方法——调用getDefaultSensor(type)并检查结果是否为null。第一种方法更适合在初始化阶段进行检查。
来自传感器的原始数据包含噪声。要平滑数据,使用低通滤波器:newValue = alpha * rawValue + (1 — alpha) * previousValue。系数alpha = 0.1-0.3在响应性和平滑度之间提供良好的平衡。对于陀螺仪,还使用高通滤波器来消除零漂移。
可以,但有局限性。从Android 8.0开始,后台应用的传感器事件频率会降低。从Android 12开始,后台访问传感器需要BODY_SENSORS_BACKGROUND权限。对于后台工作,建议使用带有通知的Foreground Service。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。