欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

传感器

程序员文章站 2022-04-30 12:00:28
...

一、引入:

手机内置的传感器是一种微型的物理设备,它能够探测、感受外界的信号,将来自真实世界的数据提供给应用程序,应用程序然后使用传感器数据向用户通知真实世界的情况,或用来控制游戏进度、或实现增强现实等。至于具体如何去利用这些信息就要充分发挥开发者的想象力了。
传感器目前已经成为了智能手机的标配。比较常见的传感器有:方向传感器、磁场传感器、温度传感器、光传感器、压力传感器、加速度传感器、重力传感器、陀螺仪传感器等。传感器就像一个个触手,不断采集着外部的信息,并将这些信息传送回手机进一步处理。在Android的特色开发技术中,除了基于位置的服务外,传感器技术绝对是最值得期待的技术。通过在Android应用中添加传感器,可以充分激发开发者的想象力,开发出各种新奇的程序。比如电子罗盘、水平仪,各种感知型游戏。

目前Android设备中可能出现的一些传感器类型包括:

  • 方向传感器
  • 磁场传感器
  • 温度传感器
  • 光传感器
  • 压力传感器
  • 加速度计
  • 距离传感器
  • 陀螺仪传感器
  • 重力传感器(Android2.3开始)
  • 线性加速度传感器(Android2.3开始)
  • 旋转矢量传感器(Android2.3开始)
  • 相对湿度传感器(Android2.3开始)
  • NFC(近场通信)传感器(Android2.3开始):NFC传感器与其他传感器不同,因为它使用与其他传感器完全不同的方式来访问。将在本书《提高篇》中单独讲解。

二、检测设备中的传感器 :

  Android SDK中定义了十多种传感器,但是不是每个手机都完全支持这些传感器。Google Nexus S支持9种传感器,HTC G7支持5种,红米手机支持9种(不支持压力、温度和相对湿度传感器)。如果手机不支持的传感器,程序运行往往不会抛出异常,只是无法获得传感器传回的数据。
    那么如何知道设备上有哪些传感器可用呢?有两种方式:一是直接的,二是间接的。

1、直接方式:
首先获取SensorManager对象,通过上下文对象的getSystemService(SENSOR_SERVICE)方法就可以获取到系统的传感器管理服务。然后调用SensorManager对象的getSensorList()方法获取传感器集合,遍历获取到的集合就能得到传感器信息。

上图为红米手机运行上述示例代码后的结果。每个item有三行文本,第一行为传感器名称,第二行为传感器类型,第三行为传感器的Vendor(即传感器提供商)。其中第二行的int值为传感器的类型,它是Sensor对象调用getType()方法的返回值。在Sensor类中定义了很多int型常量来表示传感器的类型。

表1 传感器类型

传感器

2.间接方式:
在AndroidManifest.xml配置文件中,指定该应用程序只支持运行在具有哪些硬件功能的设备上。如果应用程序需要温度传感器,可以在配置文件中添加下面一行代码:

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

Android Market只将应用程序安装在有温度传感器的设备上。但是该规则并不适用于其他Android应用商店。也就是说,一些Android应用商店不会执行检测以确保将应用程序安装在支持指定传感器的设备上。

三、使用传感器的步骤

(一)、一般使用传感器都有以下5个通用步骤:

1、调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取SensorManager对象;

2、调用SensorManager的getDefaultSensor(int type)方法获取指定类型的传感器;

3、在onCreate()生命周期方法中调用SensorManager的registerListener()方法为指定的传感器注册监听;

4、实例化SensorEventListener接口,作为registerListener()方法的第一个参数。重写SensorEventListener接口中onSensorChanged()方法;

5、在onDestroy()生命周期方法中调用SensorManager对象的unregisterListener()方法释放资源。

(二)、SensorManager的registerListener()方法的用法进行说明

public boolean registerListener(SensorEventListener listener, Sensor sensor, int rate)
参数说明如下:

  1. listener:监听传感器事件的监听器。该监听器需要实现SensorEventListener接口;
  2. sensor:通过SensorManager的getDefaultSensor(int type)方法获取到的传感器对象;
  3. rate:获取传感器数据的频率。该参数由SensorManager中的几个常量来定义。
    1)int SENSOR_DELAY_FASTEST = 0;
    以最快的速度获得传感器数据。只有特别依赖传感器数据的应用才推荐采用这种频率。这种模式会造成手机电量大量耗费。

    2)int SENSOR_DELAY_GAME = 1; 适合游戏的频率。在一般实时性要求的应用上适用这种频率。

    3)int SENSOR_DELAY_UI = 2; 适合普通用户界面的频率。这种模式比较省电,系统开销也小,但是延迟较长。

    4)int SENSOR_DELAY_NORMAL = 3; 正常频率。一般实时性要求不是特别高的应用上采用这种频率。

【注意:】
重写SensorEventListener接口中onSensorChanged(SensorEvent event)方法是实现传感器应用的关键。其中参数SensorEvent中有一个非常重要的属性:float[]类型的values数组。可以通过这个values数组取出传感器传回的数据。values数组长度为3,但不一定每一个数组元素都有意义,对于不同的传感器,每个数组元素的含义不同。

四、光传感器

光传感器的类型常量为Sensor.TYPE_LIGHT (数值为5)。values数组只有第一个元素values[0]有意义,表示光线的强度。
Android SDK中将光线强度分为不同等级,每一个等级的最大值由一个常量表示,这些常量定义在SensorManager类中。其中最大值为120000.0f。

  • public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;//最强光线强度
  • public static final float LIGHT_SUNLIGHT= 110000.0f;//万里无云阳光直射的光线强度
  • public static final float LIGHT_SHADE = 20000.0f;//阳光被云遮挡后的光线强度
  • public static final float LIGHT_OVERCAST= 10000.0f;//多云时光线强度
  • public static final float LIGHT_SUNRISE= 400.0f;//刚日出时光线强度
  • public static final float LIGHT_CLOUDY = 100.0f;//阴天无太阳时光线强度
  • public static final float LIGHT_FULLMOON= 0.25f;//夜晚满月时光线强度
  • public static final float LIGHT_NO_MOON = 0.001f;//夜晚无月亮时光线强度

五、加速度传感器

加速度传感器的类型常量为Sensor.TYPE_ACCELEROMETER (数值为1)。values数组的三个元素含义如下:

  • 1、values[0]:表示沿X轴方向的加速度(手机水平放置,手机横向左右移动);
  • 2、values[1]:表示沿Y轴方向的加速度(手机水平放置,手机前后移动);
  • 3、values[2]:表示沿Z轴方向的加速度,也就是重力加速度(手机竖向上下移动)。

图2 加速度传感器三轴示意图
传感器
接下来模仿《微信摇一摇》的功能。实现思路是:获取X、Y、Z轴三个方向上的加速度,三个方向上任何一个方向上的加速度只要大于预定值,就可以认为用户摇动了手机。当判定摇动手机后,执行:播放动画效果、同时启动震动模式、2秒后toast提示。到底这个预定加速度数值该为多大呢?考虑到重力加速度9.8m/s2,因此预定值必须大于重力加速度,所以设定为15m/s2。因为本例中用到振动,所以要给应用授予开启振动的权限。

<uses-permission android:name="android.permission.VIBRATE"/>

五、磁场传感器

磁场传感器的类型常量为Sensor.TYPE_MAGNETIC_FIELD (数值为2)。values数组的三个元素含义如下:

  • 1、values[0]:表示沿X轴方向的磁场分量,单位uT微特斯拉;
  • 2、values[1]:表示沿Y轴方向的磁场分量,单位uT微特斯拉;
  • 3、values[2]:表示沿Z轴方向的磁场分量,单位uT微特斯拉。

    磁场传感器可以检测地球的磁场,进而告诉我们北极在哪里,所以此传感器也被称为罗盘传感器。接下来拿《指南针》作为案例,来实践磁场传感器的用法。指南针的实现原理很简单,只需要检测手机围绕Z轴的旋转角度,然后对这个数值进行处理就可以了。说到这里,大家很容易想到使用方向传感器Sensor.TYPE_ORIENTATION,因为方向传感器中values[0]记录围绕Z轴的旋转角度。但是遗憾的是方向传感器Sensor.TYPE_ORIENTATION已经被废弃。目前获取手机旋转的方向和角度,Android推荐使用磁场传感器和加速度传感器共同计算得出。制作指南针效果的步骤如下:
    1.分别获取加速度传感器和磁场传感器实例,并分别注册监听器。传感器输出信息的更新速率要高一些,使用SENSOR_DELAY_GAME模式;
    2.在onSensorChanged()方法中进行判断,如果当前SensorEvent中包含的是加速度传感器,就将event中的values数组赋值给加速度传感器values数组;
    如果当前SensorEvent中包含的是磁场传感器,就将event中的values数组赋值给磁场传感器values数组。为了避免两个数组指向同一个引用,要使用clone()克隆方法;
    3.定义一个长度为9的float数组R,调用SensorManager的静态方法getRotationMatrix(),将接收自加速度传感器和罗盘传感器的数据进行计算,将计算出的旋转数据放在R数组中;
    4.定义一个长度为3的float数组values,调用SensorManager的静态方法getOrientation(),将手机在各个方向上的旋转数据都存放到values这个数组中。其中values[0]记录着手机围绕Z轴的旋转弧度,调用Math.toDegrees(values[0])方法将其转成角度值,最后对值进行处理即可。
    以上步骤涉及到两个核心方法:
    public static boolean getRotationMatrix(float[] R, float[] I,float[] gravity, float[] geomagnetic)
    作用:SensorManager的getRotationMatrix()方法,它接收来自加速度传感器和罗盘传感器的数据,然后计算出一个用于确定方向的矩阵存放到R数组中。
    参数解释:
    float[] R:是一个长度为9的float数组,当调用getRotationMatrix()方法后会将计算出的旋转数据存在该R数组中;
    float[] I:用于将地磁向量转换成重力坐标的旋转矩阵,通常指定为null即可;
    float[] gravity:加速度传感器输出的values值;
    float[] geomagnetic:磁场传感器输出的values值。
    public static float[] getOrientation(float[] R, float values[])
    作用:SensorManager的getOrientation()方法用于获取上一步中的旋转矩阵并提供一个方向矩阵。方向矩阵的值表明设备相对于地球磁场北极的旋转,以及设备相对于地面的倾斜度和摇晃。
    参数解释:
    float[] R:getRotationMatrix()方法执行后,存储了旋转数据的R数组;
    float values[]:一个长度为3的float数组。当调用SensorManager的静态方法getOrientation()后,将手机在各个方向上的旋转数据都存放到values这个数组中。其中values[0]记录着手机围绕Z轴的旋转弧度,values[1]记录着手机围绕X轴的旋转弧度,values[2]记录着手机围绕Y轴的旋转弧度。

六、方向传感器

方向传感器的类型常量为Sensor.TYPE_ORIENTATION(数值为3)。values数组的三个元素含义如下:

  • values[0]:记录手机围绕Z轴的旋转角度;
  • values[1]:记录手机围绕X轴的旋转角度;
  • values[2]:记录手机围绕Y轴的旋转角度。

方向传感器Sensor.TYPE_ORIENTATION已经被废弃。