传感器概览

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

请参阅以下相关资源:

Android 平台支持三大类传感器:

  • 移动传感器

    这类传感器测量三个轴向上的加速力和旋转力。此类别包括加速度计、重力传感器、陀螺仪和旋转矢量传感器。

  • 环境传感器

    这些传感器测量各种环境参数,例如环境气温 以及压力、照明和湿度此类别包括气压计、光度计和温度计。

  • 位置传感器

    这类传感器测量设备的物理位置。此类别包括: 方向传感器和磁力计。

您可以利用 Android 传感器框架访问设备上提供的传感器并获取原始传感器数据。传感器框架提供多个类和接口,可帮助您执行各种与传感器相关的任务。例如,您可以使用传感器框架执行以下操作:

  • 确定设备上有哪些传感器。
  • 确定单个传感器的功能,例如最大范围、制造商、功率 要求和解决方案
  • 获取原始传感器数据并定义获取传感器数据的最低频率。
  • 注册和取消注册用于监控传感器变化的传感器事件监听器。

本主题简要介绍 Android 平台所支持的传感器。以及传感器框架。

传感器简介

利用 Android 传感器框架,您可以访问多种类型的传感器。其中一些传感器 基于硬件,有些基于软件。基于硬件的传感器是构建的物理组件 手机或平板设备他们通过直接测量特定环境状况来推导出数据 例如加速度、地磁场强度或角度变化。基于软件的传感器不是物理设备,它们只是模仿基于硬件的传感器。基于软件的传感器从一个或多个基于硬件的传感器获取数据,有时被称为虚拟传感器或合成传感器。比如线性加速度传感器和重力传感器就是基于软件的传感器。表 1 总结了 Android 支持的传感器 平台。

很少有 Android 设备拥有所有类型的传感器。例如,大多数手机设备和 具有加速度计和磁力计的平板电脑,但配备 气压计或温度计此外,一个设备可以有多个特定类型的传感器。例如,一个设备可以有两个重力传感器,分别具有不同的量程。

表 1. Android 平台支持的传感器类型。

传感器 类型 说明 常见用途
TYPE_ACCELEROMETER 硬件 测量施加到设备的加速力(以 m/s2 为单位) 所有三个物理轴(x、y 和 z),包括重力。 移动侦测(摇晃、倾斜等)。
TYPE_AMBIENT_TEMPERATURE 硬件 以摄氏度 (°C) 为单位测量环境室温。请参见下面的备注。 监测气温。
TYPE_GRAVITY 软件或硬件 测量施加到所有设备的重力(以 m/s2 为单位) 三条物理轴(x、y、z)。 移动侦测(摇晃、倾斜等)。
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) 为单位。此传感器 实现方式因设备和设备而异, 此传感器已替换为以下国家/地区中的 TYPE_AMBIENT_TEMPERATURE 传感器: API 级别 14 监测温度。

传感器框架

您可以使用 Android 传感器框架访问这些传感器并获取传感器原始数据。 传感器框架是 android.hardware 软件包的一部分,包含了以下类和接口:

SensorManager
您可以使用这个类来创建传感器服务的实例。该类提供了各种方法来访问和列出传感器,注册和取消注册传感器事件监听器,以及获取屏幕方向信息。它还提供了几个传感器常量,用于报告传感器精确度,设置数据采集频率和校准传感器。
Sensor
您可以使用这个类来创建特定传感器的实例。这个类提供各种 方法,用于确定传感器的特性。
SensorEvent
系统使用此类来创建传感器事件对象,该对象会提供 传感器事件。传感器事件对象包含以下信息:原始传感器数据、 生成事件的传感器类型、数据的准确性和 事件。
SensorEventListener
您可以使用此接口创建两种回调方法,以在传感器值或传感器精确度发生变化时接收通知(传感器事件)。

在典型的应用中,您可以使用这些与传感器相关的 API 来执行两个基本任务:

  • 识别传感器和传感器特性

    如果应用具有依赖于特定传感器类型或特性的功能,则在运行时识别传感器和传感器特性非常有用。例如,您可能希望识别设备上的所有传感器,以便于停用依赖于不存在的传感器的应用功能。同样,您可能希望识别特定类型的所有传感器,以便选择可以为应用带来最佳性能的传感器实现。

  • 监控传感器事件

    您可以通过监控传感器事件来获取原始传感器数据。每当传感器检测到它所测量的参数发生变化时,就会发生传感器事件。传感器事件为您提供 4 项信息:触发事件的传感器的名称、事件的时间戳、事件的准确度以及触发事件的原始传感器数据。

传感器可用性

传感器的可用性不仅取决于设备,还取决于 Android 版本。这是因为 Android 传感器的引入历经了多个平台版本。例如,许多传感器是在 Android 1.5(API 级别 3)中引入的,但有些 未实现,且在 Android 2.3(API 级别 9)之前不可用。同样, Android 2.3(API 级别 9)和 Android 4.0(API 级别 14)中引入了多个传感器。有两个传感器已被弃用,并由更新、更好的传感器取代。

表 2 总结了每个传感器在不同平台上的可用性。这里仅列出了 4 个平台,因为只有这些平台涉及到传感器更改。被列为已废弃的传感器仍可在后续平台上使用(前提是设备上有相关传感器),这符合 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 还提供了一些方法,让您能够确定 每个传感器的功能,例如最大范围、分辨率和功率 要求。

要识别设备上的传感器,您首先需要获取对传感器的引用 服务。为此,您可以通过以下方法创建 SensorManager 类的实例: 调用 getSystemService() 方法并传递 。SENSOR_SERVICE例如:

KotlinJava
private lateinit var sensorManager: SensorManager
...
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

接下来,您可以调用 getSensorList() 方法并使用 TYPE_ALL 常量来获取设备上每种传感器的列表。例如:

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

如果您想列出特定类型的所有传感器,可以使用其他常量来代替 TYPE_ALL,例如 TYPE_GYROSCOPETYPE_LINEAR_ACCELERATIONTYPE_GRAVITY

您还可以使用 getDefaultSensor() 方法并传入特定传感器的类型常量,来确定设备上是否存在相关类型的传感器。如果设备有多个特定类型的传感器,则 必须指定为默认传感器。如果指定传感器不存在默认传感器, 某种传感器,该方法调用会返回 null,这意味着设备没有该类型的 传感器。例如,以下代码会检查设备上是否有磁力计:

KotlinJava
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.
}
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 的重力传感器。如果设备上没有该传感器,我们会尝试使用 加速度计。

KotlinJava
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
    }
}
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() 方法时,传感器返回 0,则说明传感器不是流式传感器,因为它仅在所检测的参数发生变化时才会报告数据。

getMinDelay() 方法非常有用,因为它 您可以决定 传感器用来获取数据如果应用中的某些功能需要大量流量 捕获率或流式传感器,则可以使用此方法来确定 满足这些要求,然后启用或停用应用中的相关功能 。

注意:并非传感器的最大数据采集速率 必须是传感器框架向应用传送传感器数据的速率。通过 传感器框架通过传感器事件报告数据,而几个因素会影响 您的应用将收到传感器事件。如需了解详情,请参阅监控传感器事件

监控传感器事件

如需监控原始传感器数据,您需要实现两个通过 SensorEventListener 接口公开的回调方法:onAccuracyChanged()onSensorChanged()。Android 系统调用 这些方法:

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

KotlinJava
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)
    }
}
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() 回调方法 监听器。最佳做法是始终停用不需要的传感器,尤其是在 活动已暂停。否则,可能几个小时后就会耗尽电池电量,因为某些传感器 具有很高的功耗要求,并且可能会很快耗尽电池电量。系统 在屏幕关闭时不会自动停用传感器。

处理不同的传感器配置

Android 没有为设备指定标准的传感器配置 这意味着设备制造商可以将他们需要的任何传感器配置纳入其 采用 Android 的手机。因此,设备可以包含采用各种配置的各种传感器。如果您的应用依赖于特定类型的传感器,则必须确保 传感器,以便您的应用可以成功运行。

有两种方法可以确保设备上存在特定的传感器:

  • 在运行时检测传感器,并根据需要启用或停用应用功能。
  • 使用 Google Play 过滤器定位具有特定传感器配置的设备。

下面将分别讨论这两种方法。

在运行时检测传感器

如果您的应用使用特定类型的传感器,但不依赖于它,则可以使用传感器框架在运行时检测传感器,然后根据需要停用或启用应用功能。例如,导航应用可以使用温度传感器, 压力传感器、GPS 传感器和地磁场传感器,用于显示温度、气压 压力、位置和罗盘方位。如果设备没有压力传感器,您可以使用 传感器框架在运行时检测压力传感器的缺失,然后停用 显示压力的部分。例如,以下代码会检查 设备上是否有压力传感器:

KotlinJava
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.
}
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. 传感器使用的坐标系(相对于设备) 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)或更高版本的设备上,在 具有下列限制:

  • 使用 连续 如加速度计和陀螺仪等报告模式, 事件。
  • 使用变化时触发单次报告模式的传感器不会收到事件。

考虑到这些限制,最好是在应用于前台运行或作为前台服务的一部分时检测传感器事件。

取消注册传感器监听器

使用完传感器或在传感器使用完毕后,请务必取消注册传感器的监听器 活动暂停。注册传感器监听器后,只要不取消注册传感器,那么即使监听器的 activity 已暂停,传感器仍会继续采集数据并消耗电池资源。以下 代码展示了如何使用 onPause() 方法取消注册监听器:

KotlinJava
private lateinit var sensorManager: SensorManager
...
override fun onPause() {
    super.onPause()
    sensorManager.unregisterListener(this)
}
private SensorManager sensorManager;
...
@Override
protected void onPause() {
    super.onPause();
    sensorManager.unregisterListener(this);
}

如需了解详情,请参阅 unregisterListener(SensorEventListener)

使用 Android 模拟器进行测试

Android Emulator 包含一组虚拟传感器控件, 您可以测试加速度计、环境温度计、磁力计等传感器, 例如距离、光照等

模拟器与运行 SdkController 传感器 应用。请注意,此应用仅适用于运行 Android 4.0 (API 级别 14)或更高版本。(如果设备运行的是 Android 4.0,它必须 已安装修订版 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() 方法注册传感器时,请务必选择适合您的应用或用例的提交频率。传感器能以非常高的频率提供数据。允许系统发送您不需要的额外数据,会浪费系统资源和耗费电池电量。