传感器概览

大多数 Android 设备都内置了用于测量运动、方向和各种环境条件的传感器。这些传感器能够提供高精度和高准确度的原始数据,如果您想监控设备的三维运动或位置,或者想监控设备附近环境的变化,这些传感器非常有用。例如,游戏可能会跟踪设备重力传感器的读数,以推断用户复杂的姿势和动作,例如倾斜、摇动、旋转或摆动。同样,天气应用可能会使用设备的温度传感器和湿度传感器来计算和报告露点,或者旅行应用可能会使用地磁场传感器和加速度计来报告罗盘方位。

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 硬件 测量物体相对于设备屏幕的接近程度,单位为厘米。此传感器通常用于确定手机是否正被放在人的耳边。 通话期间的手机位置。
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<Sensor> = sensorManager.getSensorList(Sensor.TYPE_ALL)

Java

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

如果您想列出给定类型的所有传感器,可以使用 TYPE_ALL 以外的其他常量,例如 TYPE_GYROSCOPETYPE_LINEAR_ACCELERATIONTYPE_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<Sensor> = sensorManager.getSensorList(Sensor.TYPE_GRAVITY)
    // 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<Sensor> gravSensors = sensorManager.getSensorList(Sensor.TYPE_GRAVITY);
    for(int i=0; i<gravSensors.size(); 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 系统会调用这些方法

以下代码展示了如何使用 onSensorChanged() 方法来监控光传感器的数据。此示例将在 main.xml 文件中定义为 sensor_dataTextView 中显示原始传感器数据。

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() 回调方法来注册和注销传感器事件监听器。作为最佳实践,您应始终禁用不需要的传感器,尤其是在您的活动暂停时。否则,可能会在短短几个小时内耗尽电池电量,因为某些传感器功耗较大,会快速消耗电池电量。当屏幕关闭时,系统不会自动禁用传感器。

It's also important to note that this example uses the onResume() and onPause() callback methods to register and unregister the sensor event listener. As a best practice you should always disable sensors you don't need, especially when your activity is paused. Failing to do so can drain the battery in just a few hours because some sensors have substantial power requirements and can use up battery power quickly. The system will not disable sensors automatically when the screen turns off.

处理不同的传感器配置

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 上发布您的应用,您可以使用清单文件中的 <uses-feature> 元素,从不具有适合您应用的传感器配置的设备中过滤掉您的应用。<uses-feature> 元素有几个硬件描述符,允许您根据特定传感器的存在来过滤应用。您可以列出的传感器包括:加速度计、气压计、罗盘(地磁场)、陀螺仪、光传感器和接近传感器。以下是一个清单条目示例,用于过滤掉没有加速度计的应用

<uses-feature android:name="android.hardware.sensor.accelerometer"
              android:required="true" />

如果您将此元素和描述符添加到应用的清单中,用户只会在设备有加速度计时才能在 Google Play 上看到您的应用。

仅当您的应用完全依赖于特定传感器时,才应将描述符设置为 android:required="true"。如果您的应用使用某个传感器实现部分功能,但即使没有该传感器也能运行,您应在 <uses-feature> 元素中列出该传感器,但将描述符设置为 android:required="false"。这有助于确保即使设备没有该特定传感器,也能安装您的应用。这同时也是一种项目管理的最佳实践,有助于您跟踪应用使用的功能。请记住,如果您的应用使用特定传感器,但即使没有该传感器也能运行,则您应在运行时检测传感器并酌情禁用或启用应用功能。

传感器坐标系

通常,传感器框架使用标准的 3 轴坐标系来表示数据值。对于大多数传感器,坐标系是相对于设备在默认方向(参见图 1)时屏幕定义的。当设备处于默认方向时,X 轴水平向右,Y 轴垂直向上,Z 轴指向屏幕外侧。在此系统中,屏幕背后的坐标具有负 Z 值。以下传感器使用此坐标系

图 1. Sensor API 使用的坐标系(相对于设备)。

关于此坐标系最重要的一点是,当设备的屏幕方向改变时,轴不会互换——也就是说,传感器的坐标系不会随着设备的移动而改变。此行为与 OpenGL 坐标系的行为相同。

另一个需要理解的点是,您的应用不得假定设备的自然(默认)方向是纵向。许多平板电脑设备的自然方向是横向。传感器坐标系始终基于设备的自然方向。

最后,如果您的应用将传感器数据与屏幕显示匹配,您需要使用 getRotation() 方法来确定屏幕旋转,然后使用 remapCoordinateSystem() 方法将传感器坐标映射到屏幕坐标。即使您的清单指定仅纵向显示,您也需要这样做。

注意:有些传感器和方法使用的坐标系是相对于世界坐标系(而不是设备坐标系)的。这些传感器和方法返回的数据表示设备相对于地球的运动或位置。欲了解更多信息,请参阅 getOrientation() 方法、getRotationMatrix() 方法、方向传感器旋转矢量传感器

传感器速率限制

为保护可能敏感的用户信息,如果您的应用面向 Android 12(API 级别 31)或更高版本,系统会对某些运动传感器和位置传感器的数据刷新率设置限制。这些数据包括设备加速度计陀螺仪地磁场传感器记录的值。

刷新率限制取决于您访问传感器数据的方式

如果您的应用需要以更高速率收集运动传感器数据,则必须声明 HIGH_SAMPLING_RATE_SENSORS 权限,如以下代码片段所示。否则,如果您的应用尝试在未声明此权限的情况下以更高速率收集运动传感器数据,则会发生 SecurityException

AndroidManifest.xml

<manifest ...>
    <uses-permission android:name="android.permission.HIGH_SAMPLING_RATE_SENSORS"/>
    <application ...>
        ...
    </application>
</manifest>

访问和使用传感器的最佳实践

在设计传感器实现时,请务必遵循本节讨论的指南。这些指南是任何使用传感器框架访问传感器和获取传感器数据的推荐最佳实践。

仅在前台收集传感器数据

在运行 Android 9(API 级别 28)或更高版本的设备上,在后台运行的应用有以下限制

  • 使用连续报告模式的传感器(如加速度计和陀螺仪)不会接收事件。
  • 使用on-changeone-shot 报告模式的传感器不会接收事件。

鉴于这些限制,最好在应用位于前台或作为前台服务的一部分时检测传感器事件。

注销传感器监听器

使用完传感器后或传感器活动暂停时,务必注销传感器监听器。如果传感器监听器已注册且其活动已暂停,传感器将继续采集数据并消耗电池资源,除非您注销该传感器。以下代码展示了如何使用 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,则必须安装 Revision 2。)SdkControllerSensor 应用监控设备上传感器的变化并将其传输到模拟器。然后,模拟器会根据从设备传感器接收到的新值进行转换。

您可以在以下位置查看 SdkControllerSensor 应用的源代码

$ your-android-sdk-directory/tools/apps/SdkController

要在您的设备和模拟器之间传输数据,请按照以下步骤操作

  1. 检查设备上是否已启用 USB 调试
  2. 使用 USB 数据线将您的设备连接到您的开发机器。
  3. 在您的设备上启动 SdkControllerSensor 应用。
  4. 在应用中,选择您要模拟的传感器。
  5. 运行以下 adb 命令

  6. $ adb forward tcp:1968 tcp:1968
    
  7. 启动模拟器。您现在应该可以通过移动设备来对模拟器应用转换。

注意: 如果您对物理设备的移动没有改变模拟器,请再次尝试运行步骤 5 中的 adb 命令。

欲了解更多信息,请参阅 Android 模拟器指南

不要阻塞 onSensorChanged() 方法

传感器数据可能以高速率变化,这意味着系统可能会频繁调用 onSensorChanged(SensorEvent) 方法。作为最佳实践,您应该在 onSensorChanged(SensorEvent) 方法中做尽可能少的事情,以免阻塞它。如果您的应用需要对传感器数据进行任何过滤或简化,您应该在 onSensorChanged(SensorEvent) 方法之外执行该工作。

避免使用已废弃的方法或传感器类型

一些方法和常量已被废弃。特别是,TYPE_ORIENTATION 传感器类型已废弃。要获取方向数据,您应该改用 getOrientation() 方法。同样,TYPE_TEMPERATURE 传感器类型已废弃。对于运行 Android 4.0 的设备,您应该改用 TYPE_AMBIENT_TEMPERATURE 传感器类型。

使用前验证传感器

在尝试从传感器获取数据之前,务必验证设备上是否存在该传感器。不要仅仅因为某个传感器常用就假定其存在。设备制造商没有义务在其设备中提供任何特定的传感器。

仔细选择传感器延迟

使用 registerListener() 方法注册传感器时,请务必选择适合您的应用或用例的传递速率。传感器可以以非常高的速率提供数据。允许系统发送您不需要的额外数据会浪费系统资源并消耗电池电量。