Android 传感器概述(一)

Android 传感器概述(一)

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

Android 平台支持三大类传感器

  • 动态传感器
    这类传感器测量三个轴向上的加速力和旋转力。这个类别中包含加速度计、重力传感器、陀螺仪和旋转矢量传感器。
  • 环境传感器
    这类传感器测量各种环境参数,如环境气温、气压、照度和湿度。这个类别中包含气压计、光度计和温度计
  • 位置传感器
    这类传感器测量设备的物理位置。这个类别中包含屏幕方向传感器和磁力计。

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

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

传感器简介

利用 Android 传感器框架,您可以访问多种类型的传感器。有些传感器基于硬件,有些基于软件。基于硬件的传感器是内置在手机或平板设备中的物理组件。这类传感器通过直接测量特定的环境属性(如加速度、地磁场强度或角度变化)来采集数据。基于软件的传感器不是物理设备,它们只是模仿基于硬件的传感器。基于软件的传感器从一个或多个基于硬件的传感器获取数据,有时被称为虚拟传感器或合成传感器。比如线性加速度传感器和重力传感器就是基于软件的传感器。

很少有 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
    使用这个类来创建传感器服务的实例。该类提供了各种方法来访问和列出传感器,注册和取消注册传感器事件监听器,以及获取屏幕方向信息。它还提供了几个传感器常量,用于报告传感器精确度,设置数据采集频率和校准传感器。

  • Sensor
    使用这个类来创建特定传感器的实例。该类提供了各种方法来确定传感器的特性。

  • SensorEvent
    使用这个类来创建传感器事件对象,该对象提供有关传感器事件的信息。传感器事件对象中包含以下信息:原始传感器数据、生成事件的传感器类型、数据的准确度和事件的时间戳。

  • SensorEventListener
    使用此接口创建两种回调方法,以在传感器值或传感器精确度发生变化时接收通知(传感器事件)。
    在典型的应用中,可以使用这些与传感器相关的 API 来执行两个基本任务:

    • 识别传感器和传感器特性
      如果应用具有依赖于特定传感器类型或特性的功能,则在运行时识别传感器和传感器特性非常有用。例如,希望识别设备上的所有传感器,以便于停用依赖于不存在的传感器的应用功能。同样,可能希望识别特定类型的所有传感器,以便选择可以为应用带来最佳性能的传感器实现。
    • 监控传感器事件
      通过监控传感器事件来获取原始传感器数据。每当传感器检测到它所测量的参数发生变化时,就会发生传感器事件。传感器事件为您提供 4 项信息:触发事件的传感器的名称、事件的时间戳、事件的准确度以及触发事件的原始传感器数据。

识别传感器和传感器特性

Android 传感器框架提供了几个方法,可让您在运行时轻松确定设备上有哪些传感器。该 API 还提供了相关方法来确定每个传感器的特性,例如最大量程、分辨率和功率要求。

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

private SensorManager sensorManager;
...
sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    

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

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

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

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

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.
}

监控传感器事件

要监控原始传感器数据,您需要实现两个通过 SensorEventListener 接口公开的回调方法:onAccuracyChanged()onSensorChanged()。Android 系统会在发生以下情况时调用这两个方法:

  • 传感器的准确度发生了变化
    在这种情况下,系统会调用 onAccuracyChanged() 方法,为您提供对于发生变化的 Sensor 对象的引用以及传感器的新准确度。准确度由以下 4 个状态常量之一表示:SENSOR_STATUS_ACCURACY_LOWSENSOR_STATUS_ACCURACY_MEDIUMSENSOR_STATUS_ACCURACY_HIGHSENSOR_STATUS_UNRELIABLE
  • 传感器报告了新值
    在这种情况下,系统会调用 onSensorChanged() 方法,为您提供 SensorEvent 对象。SensorEvent 对象包含关于新传感器数据的信息,包括:数据的准确度、生成数据的传感器、生成数据的时间戳以及传感器记录的新数据。

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

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 系统和其他应用可以更改此延迟。最佳做法是指定尽可能大的延迟,因为系统通常会使用比指定的延迟更小的延迟(也就是说,应该选择能够满足应用需求的最低采样率)。使用更大的延迟可以降低处理器的负载,从而降低功耗。

采样率(延迟)一旦设置,就不应该再更改。如果由于某种原因确实需要更改延迟,则必须取消注册再重新注册传感器监听器。

另外还需要注意的是,本示例使用 onResume()onPause() 回调方法来注册和取消注册传感器事件监听器。最佳的做法是始终停用不需要的传感器,特别是在活动处于暂停状态时。如果不这样做,可能会在几小时内将电池电量耗尽,因为有些传感器的电量需求很大,可以很快耗尽电池电量。当屏幕关闭时,系统不会自动停用传感器。

处理不同的传感器配置

Android 没有为设备指定标准的传感器配置,这意味着设备制造商可以在其 Android 设备中采用任何想要的传感器配置。因此,设备可以包含采用各种配置的各种传感器。如果您的应用依赖于特定类型的传感器,则必须确保设备上存在该传感器,这样您的应用才能成功运行。

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

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

在运行时检测传感器

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

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 轴坐标系来表示数据值。对于大多数传感器,当设备处于默认屏幕方向时,会相对于设备屏幕来定义坐标系。当设备处于默认屏幕方向时,X 轴为水平向右延伸,Y 轴为垂直向上延伸,Z 轴为垂直于屏幕向外延伸。在此坐标系中,屏幕后面的坐标将具有负 Z 值。以下传感器使用此坐标系:加速度传感器,重力传感器,陀螺仪,线性加速度传感器,地磁场传感器。
在这里插入图片描述
关于此坐标系,特别需要注意的一点就是当设备的屏幕方向改变时,坐标轴不会转换,也就是说,传感器的坐标系不会随着设备的移动而改变。此行为与 OpenGL 坐标系的行为是相同的。

还需要注意的一点是,应用不能假设设备的自然(默认)屏幕方向是竖屏。许多平板设备的自然屏幕方向为横屏。传感器坐标系始终基于设备的自然屏幕方向。

最后,如果应用将传感器数据对应到屏幕显示,需要使用 getRotation() 方法确定屏幕的旋转度,然后使用 remapCoordinateSystem() 方法将传感器坐标映射到屏幕坐标。即使清单指定了仅限竖屏显示,也需要这样做。

猜你喜欢

转载自blog.csdn.net/tracydragonlxy/article/details/128410934