大多数 Android 设备都有内置传感器,用来测量动作、方向和各种环境条件。这些传感器能够提供高精度和准确性的原始数据,如果您想监控三维设备运动或定位,或者想监控设备附近的周围环境变化,这些传感器非常有用。例如,游戏可能会跟踪设备重力传感器的读数,以推断复杂的用户手势和动作,如倾斜、摇晃、旋转或挥动。同样,天气应用可能会使用设备的温度传感器和湿度传感器来计算和报告露点,或者旅行应用可能会使用地磁场传感器和加速度计来报告指南针方位。
请参阅以下相关资源
传感器
动作传感器
位置传感器
环境传感器
API 演示 (OS - RotationVectorDemo)
Android 平台支持三大类传感器:
动作传感器动作传感器测量沿三个轴的加速力和旋转力。此类包括加速度计、重力传感器、陀螺仪和旋转矢量传感器。
环境传感器这些传感器测量各种环境参数,例如环境空气温度和压力、光照和湿度。此类包括气压计、光度计和温度计。
位置传感器位置传感器测量设备的物理位置。此类包括方向传感器和磁力计。
您可以通过使用 Android 传感器框架来访问设备上可用的传感器并获取原始传感器数据。传感器框架提供了多个类和接口,可帮助您执行各种与传感器相关的任务。例如,您可以使用传感器框架执行以下操作:
确定设备上有哪些传感器可用。
确定单个传感器的功能,例如其最大范围、制造商、功率要求和分辨率。
获取原始传感器数据,并定义获取传感器数据的最小速率。
注册和注销用于监控传感器变化的传感器事件监听器。
本主题概述了 Android 平台上可用的传感器。它还介绍了传感器框架。
传感器简介
Android 传感器框架可让您访问多种类型的传感器。其中一些传感器是基于硬件的,另一些是基于软件的。硬件传感器是内置在手机或平板电脑设备中的物理组件。它们通过直接测量特定的环境属性(如加速度、地磁场强度或角度变化)来得出数据。软件传感器不是物理设备,尽管它们模仿硬件传感器。软件传感器从一个或多个硬件传感器中获取数据,有时被称为虚拟传感器或合成传感器。线性加速度传感器和重力传感器就是软件传感器的例子。表 1 总结了 Android 平台支持的传感器。
很少有 Android 设备拥有每种类型的传感器。例如,大多数手机设备和平板电脑都有加速度计和磁力计,但拥有气压计或温度计的设备较少。此外,一个设备可以拥有多个给定类型的传感器。例如,一个设备可以有两个重力传感器,每个传感器具有不同的范围。
表 1. Android 平台支持的传感器类型。
传感器
类型
描述
常见用途
TYPE_ACCELEROMETER
硬件
测量应用于设备所有三个物理轴(x、y 和 z)的加速度(以 m/s2 为单位),包括重力。
动作检测(摇晃、倾斜等)。
TYPE_AMBIENT_TEMPERATURE
硬件
测量环境室温(以摄氏度 °C 为单位)。请参阅下面的说明。
监测气温。
TYPE_GRAVITY
软件或硬件
测量应用于设备所有三个物理轴(x、y、z)的重力(以 m/s2 为单位)。
动作检测(摇晃、倾斜等)。
TYPE_GYROSCOPE
硬件
测量设备绕三个物理轴(x、y 和 z)中每一个的旋转速率(以 rad/s 为单位)。
旋转检测(旋转、转动等)。
TYPE_LIGHT
硬件
测量环境光水平(照明度),以 lx 为单位。
控制屏幕亮度。
TYPE_LINEAR_ACCELERATION
软件或硬件
测量应用于设备所有三个物理轴(x、y 和 z)的加速度(以 m/s2 为单位),不包括重力。
沿单个轴监测加速度。
TYPE_MAGNETIC_FIELD
硬件
测量所有三个物理轴(x、y、z)的环境地磁场,以 μT 为单位。
创建指南针。
TYPE_ORIENTATION
软件
测量设备绕所有三个物理轴(x、y、z)旋转的度数。从 API 级别 3 开始,您可以使用重力传感器和地磁场传感器并结合 getRotationMatrix() 方法来获取设备的倾斜矩阵和旋转矩阵。
确定设备位置。
TYPE_PRESSURE
硬件
测量环境空气压力,以 hPa 或 mbar 为单位。
监测气压变化。
TYPE_PROXIMITY
硬件
测量物体相对于设备显示屏的接近程度(以 cm 为单位)。此传感器通常用于确定手机是否贴在人的耳朵上。
通话期间的手机位置。
TYPE_RELATIVE_HUMIDITY
硬件
测量相对环境湿度(以百分比 % 为单位)。
监测露点、绝对湿度和相对湿度。
TYPE_ROTATION_VECTOR
软件或硬件
通过提供设备旋转矢量的三个元素来测量设备的方向。
动作检测和旋转检测。
TYPE_TEMPERATURE
硬件
测量设备的温度(以摄氏度 °C 为单位)。此传感器的实现在不同设备上有所不同,并且此传感器在 API 级别 14 中已被 TYPE_AMBIENT_TEMPERATURE 传感器取代。
监测温度。
传感器框架
您可以通过使用 Android 传感器框架来访问这些传感器并获取原始传感器数据。传感器框架是 android.hardware 包的一部分,包括以下类和接口:
SensorManager
您可以使用此类来创建传感器服务的实例。此类提供了各种方法,用于访问和列出传感器、注册和注销传感器事件监听器以及获取方向信息。此类还提供了几个传感器常量,用于报告传感器精度、设置数据获取速率和校准传感器。
传感器
您可以使用此类来创建特定传感器的实例。此类提供了各种方法,让您确定传感器的功能。
SensorEvent
系统使用此类来创建传感器事件对象,该对象提供有关传感器事件的信息。传感器事件对象包含以下信息:原始传感器数据、生成事件的传感器类型、数据的精度以及事件的时间戳。
SensorEventListener
您可以使用此接口创建两个回调方法,当传感器值发生变化或传感器精度发生变化时,这些方法会接收通知(传感器事件)。
在典型的应用程序中,您使用这些与传感器相关的 API 来执行两项基本任务:
识别传感器和传感器功能
如果您的应用程序具有依赖于特定传感器类型或功能的特性,则在运行时识别传感器和传感器功能非常有用。例如,您可能希望识别设备上存在的所有传感器,并禁用任何依赖于不存在的传感器的应用程序功能。同样,您可能希望识别给定类型的所有传感器,以便您可以选择具有最适合您应用程序性能的传感器实现。
监控传感器事件
监控传感器事件是获取原始传感器数据的方式。每当传感器检测到其测量的参数发生变化时,就会发生传感器事件。传感器事件为您提供四条信息:触发事件的传感器名称、事件的时间戳、事件的精度以及触发事件的原始传感器数据。
传感器可用性
虽然传感器的可用性因设备而异,但也可能因 Android 版本而异。这是因为 Android 传感器是在多个平台发布过程中逐步引入的。例如,许多传感器在 Android 1.5 (API 级别 3) 中引入,但有些传感器直到 Android 2.3 (API 级别 9) 才实现并可供使用。同样,在 Android 2.3 (API 级别 9) 和 Android 4.0 (API 级别 14) 中也引入了多个传感器。两个传感器已被弃用并被更新、更好的传感器所取代。
表 2 总结了每个传感器在各平台上的可用性。仅列出了四个平台,因为这些是涉及传感器更改的平台。被列为弃用的传感器在后续平台上仍然可用(前提是设备上存在该传感器),这符合 Android 的向前兼容政策。
表 2. 传感器按平台的可用性。
传感器
Android 4.0(API 级别 14)
Android 2.3(API 级别 9)
Android 2.2(API 级别 8)
Android 1.5(API 级别 3)
TYPE_ACCELEROMETER
是
是
是
是
TYPE_AMBIENT_TEMPERATURE
是
不适用
不适用
不适用
TYPE_GRAVITY
是
是
不适用
不适用
TYPE_GYROSCOPE
是
是
不适用1
不适用1
TYPE_LIGHT
是
是
是
是
TYPE_LINEAR_ACCELERATION
是
是
不适用
不适用
TYPE_MAGNETIC_FIELD
是
是
是
是
TYPE_ORIENTATION
是2
是2
是2
是
TYPE_PRESSURE
是
是
不适用1
不适用1
TYPE_PROXIMITY
是
是
是
是
TYPE_RELATIVE_HUMIDITY
是
不适用
不适用
不适用
TYPE_ROTATION_VECTOR
是
是
不适用
不适用
TYPE_TEMPERATURE
是2
是
是
是
1 此传感器类型是在 Android 1.5 (API 级别 3) 中添加的,但直到 Android 2.3 (API 级别 9) 才可供使用。
2 此传感器可用,但已被弃用。
识别传感器和传感器功能
Android 传感器框架提供了几种方法,可让您在运行时轻松确定设备上有哪些传感器。该 API 还提供了让您确定每个传感器功能的方法,例如其最大范围、分辨率和功率要求。
要识别设备上的传感器,您首先需要获取传感器服务的引用。为此,您可以通过调用 getSystemService() 方法并传入 SENSOR_SERVICE 参数来创建 SensorManager 类的实例。例如:
Kotlin
private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
Java
private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
接下来,您可以通过调用 getSensorList() 方法并使用 TYPE_ALL 常量来获取设备上每个传感器的列表。例如:
Kotlin
val deviceSensors: List
Java
List
如果您想列出所有给定类型的传感器,可以使用其他常量而不是 TYPE_ALL,例如 TYPE_GYROSCOPE、TYPE_LINEAR_ACCELERATION 或 TYPE_GRAVITY。
您还可以使用 getDefaultSensor() 方法并传入特定传感器的类型常量来确定设备上是否存在特定类型的传感器。如果设备有多个给定类型的传感器,则必须将其中一个传感器指定为默认传感器。如果给定类型的传感器不存在默认传感器,则方法调用返回 null,这意味着设备没有该类型的传感器。例如,以下代码检查设备上是否有磁力计:
Kotlin
private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null) {
// Success! There's a magnetometer.
} else {
// Failure! No magnetometer.
}
Java
private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
// Success! There's a magnetometer.
} else {
// Failure! No magnetometer.
}
注意:Android 不要求设备制造商在其 Android 设备中内置任何特定类型的传感器,因此设备的传感器配置可能大不相同。
除了列出设备上的传感器外,您还可以使用 Sensor 类的公共方法来确定单个传感器的功能和属性。如果您希望应用程序根据设备上可用的传感器或传感器功能表现出不同的行为,这很有用。例如,您可以使用 getResolution() 和 getMaximumRange() 方法获取传感器的分辨率和最大测量范围。您还可以使用 getPower() 方法获取传感器的功率要求。
如果您想针对不同制造商的传感器或传感器的不同版本优化应用程序,有两个公共方法特别有用。例如,如果您的应用程序需要监测用户手势(如倾斜和摇晃),您可以为具有特定供应商重力传感器的较新设备创建一套数据过滤规则和优化方案,并为没有重力传感器且只有加速度计的设备创建另一套数据过滤规则和优化方案。以下代码示例展示了如何使用 getVendor() 和 getVersion() 方法来执行此操作。在此示例中,我们正在寻找一个供应商列表显示为 Google LLC 且版本号为 3 的重力传感器。如果该特定传感器不存在于设备上,我们尝试使用加速度计。
Kotlin
private lateinit var sensorManager: SensorManager
private var mSensor: Sensor? = null
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null) {
val gravSensors: List
// Use the version 3 gravity sensor.
mSensor = gravSensors.firstOrNull { it.vendor.contains("Google LLC") && it.version == 3 }
}
if (mSensor == null) {
// Use the accelerometer.
mSensor = if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null) {
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
} else {
// Sorry, there are no accelerometers on your device.
// You can't play this game.
null
}
}
Java
private SensorManager sensorManager;
private Sensor mSensor;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;
if (sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
List
for(int i=0; i if ((gravSensors.get(i).getVendor().contains("Google LLC")) && (gravSensors.get(i).getVersion() == 3)){ // Use the version 3 gravity sensor. mSensor = gravSensors.get(i); } } } if (mSensor == null){ // Use the accelerometer. if (sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){ mSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER); } else{ // Sorry, there are no accelerometers on your device. // You can't play this game. } } 另一个有用的方法是 getMinDelay() 方法,它返回传感器感知数据的最小时间间隔(以微秒为单位)。任何为 getMinDelay() 方法返回非零值的传感器都是流式传感器。流式传感器以固定时间间隔感知数据,它们是在 Android 2.3 (API 级别 9) 中引入的。如果在调用 getMinDelay() 方法时传感器返回零,这意味着该传感器不是流式传感器,因为它仅在其感知的参数发生变化时才报告数据。 getMinDelay() 方法很有用,因为它可以让您确定传感器获取数据的最大速率。如果您的应用程序中的某些功能需要高数据获取速率或流式传感器,您可以使用此方法确定传感器是否满足这些要求,然后相应地启用或禁用应用程序中的相关功能。 警告:传感器的最大数据获取速率不一定是传感器框架向您的应用程序传递传感器数据的速率。传感器框架通过传感器事件报告数据,有几个因素会影响应用程序接收传感器事件的速率。有关详细信息,请参阅监控传感器事件。 监控传感器事件 要监控原始传感器数据,您需要实现通过 SensorEventListener 接口公开的两个回调方法:onAccuracyChanged() 和 onSensorChanged()。每当发生以下情况时,Android 系统都会调用这些方法: 传感器的精度发生变化。 在这种情况下,系统会调用 onAccuracyChanged() 方法,为您提供对发生变化的 Sensor 对象的引用以及传感器的新精度。精度由四个状态常量之一表示:SENSOR_STATUS_ACCURACY_LOW、SENSOR_STATUS_ACCURACY_MEDIUM、SENSOR_STATUS_ACCURACY_HIGH 或 SENSOR_STATUS_UNRELIABLE。 传感器报告一个新值。 在这种情况下,系统会调用 onSensorChanged() 方法,为您提供一个 SensorEvent 对象。一个 SensorEvent 对象包含有关新传感器数据的信息,包括:数据的精度、产生数据的传感器、产生数据的时间戳以及传感器记录的新数据。 以下代码展示了如何使用 onSensorChanged() 方法来监控来自光传感器的数据。本例中,在 main.xml 文件中定义为 sensor_data 的 TextView 中显示原始传感器数据。 Kotlin class SensorActivity : Activity(), SensorEventListener { private lateinit var sensorManager: SensorManager private var mLight: Sensor? = null public override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.main) sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT) } override fun onAccuracyChanged(sensor: Sensor, accuracy: Int) { // Do something here if sensor accuracy changes. } override fun onSensorChanged(event: SensorEvent) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. val lux = event.values[0] // Do something with this sensor value. } override fun onResume() { super.onResume() mLight?.also { light -> sensorManager.registerListener(this, light, SensorManager.SENSOR_DELAY_NORMAL) } } override fun onPause() { super.onPause() sensorManager.unregisterListener(this) } } Java public class SensorActivity extends Activity implements SensorEventListener { private SensorManager sensorManager; private Sensor mLight; @Override public final void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); mLight = sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT); } @Override public final void onAccuracyChanged(Sensor sensor, int accuracy) { // Do something here if sensor accuracy changes. } @Override public final void onSensorChanged(SensorEvent event) { // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. float lux = event.values[0]; // Do something with this sensor value. } @Override protected void onResume() { super.onResume(); sensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL); } @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } } 在此示例中,在调用 registerListener() 方法时指定了默认数据延迟 (SENSOR_DELAY_NORMAL)。数据延迟(或采样率)控制通过 onSensorChanged() 回调方法将传感器事件发送到应用程序的时间间隔。默认数据延迟适用于监控典型的屏幕方向更改,并使用 200,000 微秒的延迟。您可以指定其他数据延迟,例如 SENSOR_DELAY_GAME (20,000 微秒延迟)、SENSOR_DELAY_UI (60,000 微秒延迟) 或 SENSOR_DELAY_FASTEST (0 微秒延迟)。从 Android 3.0 (API 级别 11) 开始,您还可以将延迟指定为绝对值(以微秒为单位)。 您指定的延迟仅是建议的延迟。Android 系统和其他应用程序可以更改此延迟。最佳做法是,您应该指定尽可能大的延迟,因为系统通常使用比您指定的延迟更小的延迟(也就是说,您应该选择仍能满足应用程序需求的最慢采样率)。使用较大的延迟可以降低处理器的负载,从而减少耗电量。 没有公共方法用于确定传感器框架向您的应用程序发送传感器事件的速率;但是,您可以使用与每个传感器事件相关联的时间戳来计算多个事件的采样率。设置采样率(延迟)后,您通常不需要再更改。如果由于某种原因您确实需要更改延迟,则必须注销并重新注册传感器监听器。 同样重要的一点是,此示例使用 onResume() 和 onPause() 回调方法来注册和注销传感器事件监听器。作为最佳做法,您应始终在不需要时禁用传感器,尤其是在您的 Activity 处于暂停状态时。如果不这样做,可能会在短短几个小时内耗尽电池,因为某些传感器具有巨大的功率需求,并且会迅速耗尽电池电量。当屏幕关闭时,系统不会自动禁用传感器。 处理不同的传感器配置 Android 不为设备指定标准传感器配置,这意味着设备制造商可以在其 Android 设备中加入他们想要的任何传感器配置。因此,设备可以包含各种配置的各种传感器。如果您的应用程序依赖于特定类型的传感器,您必须确保设备上存在该传感器,以便您的应用程序成功运行。 您有两种方案可确保设备上存在给定传感器: 在运行时检测传感器,并根据需要启用或禁用应用程序功能。 使用 Google Play 过滤器定位具有特定传感器配置的设备。 以下各节将讨论每个方案。 在运行时检测传感器 如果您的应用程序使用特定类型的传感器,但不依赖于它,则可以使用传感器框架在运行时检测该传感器,然后根据需要禁用或启用应用程序功能。例如,导航应用程序可能会使用温度传感器、压力传感器、GPS 传感器和地磁场传感器来显示温度、气压、位置和指南针方位。如果设备没有压力传感器,您可以在运行时使用传感器框架检测压力传感器的缺失,然后禁用应用程序 UI 中显示压力的部分。例如,以下代码检查设备上是否存在压力传感器: Kotlin private lateinit var sensorManager: SensorManager ... sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null) { // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. } Java private SensorManager sensorManager; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); if (sensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){ // Success! There's a pressure sensor. } else { // Failure! No pressure sensor. } 使用 Google Play 过滤器定位特定的传感器配置 如果您在 Google Play 上发布应用程序,可以在清单文件中使用 android:required="true" /> 如果您在应用程序的清单中添加此元素和描述符,则只有在用户的设备具有加速度计的情况下,用户才会在 Google Play 上看到您的应用程序。 只有当您的应用程序完全依赖于特定传感器时,才应将描述符设置为 android:required="true"。如果您的应用程序使用传感器来实现某些功能,但在没有传感器的情况下仍能运行,则应在 传感器坐标系 通常,传感器框架使用标准的三轴坐标系来表示数据值。对于大多数传感器,坐标系是相对于设备屏幕定义的(当设备处于其默认方向时,见图 1)。当设备处于默认方向时,X 轴水平指向右侧,Y 轴垂直向上,Z 轴指向屏幕表面的外侧。在这个系统中,屏幕后面的坐标具有负的 Z 值。以下传感器使用此坐标系: 图 1. 传感器 API 使用的坐标系(相对于设备)。 加速度传感器 重力传感器 陀螺仪 线性加速度传感器 地磁场传感器 关于此坐标系,最重要的一点是要理解:当设备屏幕方向发生变化时,轴不会发生交换——也就是说,传感器的坐标系永远不会随着设备的移动而改变。这种行为与 OpenGL 坐标系的行为相同。 另一点需要理解的是,您的应用程序不能假设设备的自然(默认)方向是纵向。对于许多平板电脑设备来说,自然方向是横向。而且传感器的坐标系始终基于设备的自然方向。 最后,如果您的应用程序将传感器数据与屏幕显示相匹配,则需要使用 getRotation() 方法确定屏幕旋转,然后使用 remapCoordinateSystem() 方法将传感器坐标映射到屏幕坐标。即使您的清单指定仅纵向显示,您也需要这样做。 注意:某些传感器和方法使用的坐标系是相对于世界参考框架的(而不是相对于设备参考框架)。这些传感器和方法返回的数据代表设备相对于地球的运动或位置。有关详细信息,请参阅 getOrientation() 方法、getRotationMatrix() 方法、方向传感器和旋转矢量传感器。 传感器频率限制 为了保护用户潜在的敏感信息,如果您的应用以 Android 12 (API 级别 31) 或更高版本为目标,系统会对来自某些动作传感器和位置传感器的数据刷新率施加限制。这些数据包括由设备的加速度计、陀螺仪和地磁场传感器记录的值。 刷新率限制取决于您如何访问传感器数据: 如果您调用 registerListener() 方法来监控传感器事件,则传感器采样率限制为 200 Hz。这适用于 registerListener() 方法的所有重载变体。 如果您使用 SensorDirectChannel 类,则传感器采样率限制为 RATE_NORMAL,通常约为 50 Hz。 如果您的应用需要以更高的频率收集动作传感器数据,则必须声明 HIGH_SAMPLING_RATE_SENSORS 权限,如以下代码片段所示。否则,如果您的应用在未声明此权限的情况下尝试以更高频率收集动作传感器数据,则会发生 SecurityException。 AndroidManifest.xml ... 注意:如果用户使用设备开关关闭了麦克风访问权限,则无论您是否声明了 HIGH_SAMPLING_RATE_SENSORS 权限,动作传感器和位置传感器的频率始终会受到限制。 访问和使用传感器的最佳做法 在设计传感器实现时,请务必遵循本节中讨论的指南。这些指南是向任何使用传感器框架访问传感器和获取传感器数据的人推荐的最佳做法。 仅在前台收集传感器数据 在运行 Android 9 (API 级别 28) 或更高版本的设备上,后台运行的应用具有以下限制: 使用 连续报告模式的传感器(如加速度计和陀螺仪)不会接收到事件。 使用 变化时报告 (on-change) 或 单次报告 (one-shot) 模式的传感器不会接收到事件。 鉴于这些限制,最好在应用位于前台或作为前台服务的一部分时检测传感器事件。 注销传感器监听器 使用完传感器或传感器 Activity 暂停时,请务必注销传感器的监听器。如果注册了传感器监听器且其 Activity 已暂停,除非您注销传感器,否则传感器将继续获取数据并消耗电池资源。以下代码显示了如何使用 onPause() 方法注销监听器: Kotlin private lateinit var sensorManager: SensorManager ... override fun onPause() { super.onPause() sensorManager.unregisterListener(this) } Java private SensorManager sensorManager; ... @Override protected void onPause() { super.onPause(); sensorManager.unregisterListener(this); } 有关详细信息,请参阅 unregisterListener(SensorEventListener)。 使用 Android 模拟器进行测试 Android 模拟器包含一组虚拟传感器控件,可让您测试加速度计、环境温度、磁力计、近距离、光等传感器。 该模拟器通过与运行 SdkControllerSensor 应用的 Android 设备建立连接来使用。请注意,此应用仅在运行 Android 4.0 (API 级别 14) 或更高版本的设备上可用。(如果设备运行 Android 4.0,则必须安装修订版 2。)SdkControllerSensor 应用监控设备上传感器的变化并将其传输到模拟器。然后,模拟器根据从设备传感器接收的新值进行变换。 您可以在以下位置查看 SdkControllerSensor 应用的源代码: $ your-android-sdk-directory/tools/apps/SdkController 要在设备和模拟器之间传输数据,请按以下步骤操作: 检查设备上是否启用了 USB 调试。 使用 USB 线将设备连接到开发机器。 在设备上启动 SdkControllerSensor 应用。 在应用中,选择要模拟的传感器。 运行以下 adb 命令: $ adb forward tcp:1968 tcp:1968 启动模拟器。您现在应该能够通过移动设备对模拟器应用变换。 注意:如果您对物理设备所做的移动没有使模拟器发生变换,请尝试再次运行第 5 步中的 adb 命令。 有关详细信息,请参阅 Android 模拟器指南。 不要阻塞 onSensorChanged() 方法 传感器数据变化频率可能很高,这意味着系统可能会频繁调用 onSensorChanged(SensorEvent) 方法。作为最佳做法,您应该在 onSensorChanged(SensorEvent) 方法中尽可能少做工作,以免阻塞它。如果您的应用程序需要执行任何数据过滤或传感器数据约减,则应在 onSensorChanged(SensorEvent) 方法之外执行该工作。 避免使用弃用的方法或传感器类型 多种方法和常量已被弃用。尤其是 TYPE_ORIENTATION 传感器类型已被弃用。要获取方向数据,应改用 getOrientation() 方法。同样,TYPE_TEMPERATURE 传感器类型也已被弃用。在运行 Android 4.0 的设备上,您应该改用 TYPE_AMBIENT_TEMPERATURE 传感器类型。 在使用传感器之前进行验证 在尝试从传感器获取数据之前,请始终验证该传感器在设备上是否存在。不要仅仅因为它是常用传感器就假设它存在。设备制造商不需要在他们的设备中提供任何特定的传感器。 仔细选择传感器延迟 使用 registerListener() 方法注册传感器时,请务必选择适合您的应用程序或用例的传递速率。传感器可以以非常高的速率提供数据。允许系统发送您不需要的额外数据会浪费系统资源并消耗电池电量。