现代智能手机承载的功能已远远超出了通信这一传统功能。外部传感器可以报告手机所处的环境,这使得手机对于用户及开发人员都更强大和有用。从Android 1.5(API level 3)开始,提供了标准的传感器集合。物理传感器包括但是不限于加速度计,它衡量沿着各条轴的加速度;测量某些轴的旋转变化的陀螺仪;沿着某条轴感应磁场强度的磁场传感器;衡量环境光强度的光传感器;衡量外部对象到设备的距离的距离传感器;测量环境温度的温度传感器;以及作为晴雨表的压力传感器等。每个传感器的直接输出测量值可以认为是原始指标,因此关联的传感器是原始传感器(raw sensor)。通过某些传感器,可以组合或汇集多个衡量指标,在这些指标上可以执行计算,形成更复杂的指标。例如,通过整合随时间推移旋转变化的陀螺仪指标,可以生成旋转向量。这类复杂的衡量指标往往来自组合的传感器。
Android提供了SensorManager系统服务来支持对一个或一组传感器的访问。该系统服务可以通过Context的getSystemService方法访问,其参数是Context.SENSOR_SERVICE。使用SensorManager,可以通过getDefaultSensor方法获取特定的传感器。
但是,有时可以返回组合的传感器,因此,如果想访问原始传感器及其关联的数据,应该使用getSensorList方法:
SensorManager mngr = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);// getting the default accelerometerSensor accel = mngr.getDefaultSensor (Sensor.TYPE_ACCELEROMETER);// getting the raw accelerometerList<Sensor> list = mngr.getSensorList(Sensor.TYPE_ACCELEROMETER);
一旦获取到了一个或一组传感器,就可以启用这些传感器,首先需要在传感器上注册数据。数据应该是按照参数中提供的速率获取,数据获取速率值可以是SENSOR_DELAY_NORMAL、SENSOR_DELAY_UI(用于基础的UI交互的速率)、SENSOR_DELAY_GAME(适用于有些高速率),SENSOR_DELAY_FASTEST(速率越快越好),或者以ms表示的事件之间的具体延迟:
SensorEventListener listener = new SensorEventListener { @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } @Override public void onSensorChanged(SensorEvent event) { }};// registering a listenermngr.registerListener(listener, sensor, SensorManager.SENSOR_DELAY_UI);
SensorEventListener中提供的两个方法,onAccuracyChanged和onSensorChanged是当数据在传感器中可用时调用的。当传感器错误或准确度级别变动时,会调用onAccuracyChanged方法。onSensorChanged方法可能是更有意思的方法,在该方法中,传感器所收集的数据是封装在SensorEvent对象中传递的。
注销监听器并且在不需要的时候禁用传感器是非常重要的(例如暂停活动);否则,设备会继续运转,消耗电源。即使关闭屏幕,系统也不会替你执行注销操作:
mngr.unregisterListener(listener);
当打开传感器时,SensorEvent是通过onSensorChanged方法传递给传感器的。每种传感器类型的SensorEvent值不同。
位置
手机的坐标系统是基于屏幕和手机屏幕的默认方向。x轴、y轴和z轴如图17-1所示,工作机理如下:
x轴
水平方向,取值向右递增,向左递减。
y轴
垂直方向,取值向上递增,向下递减。
z轴
和屏幕垂直的轴,从屏幕向前值为正,向后值为负(z轴的零点落在屏幕上)。
当用户移动手机时,轴会随着手机运动,不会变换位置。
图17-1:手机的坐标系统
各种传感器的精度和方差取决于硬件的质量。在很多情况下,需要消除显著的抖动/噪声数据(例如使用低音滤波器)。过滤器及其构建类型取决于设计和构建的开发人员。
加速度计
加速度计用于检测设备的加速度,返回沿着3条轴的值(value[0]表示x轴值,value[1]表示y轴值,value[2]表示z轴值)。这些值的单位是SI(m/S 2)。注意,重力没有从返回的值中排除。因此,当设备放置在桌子上时,value[2]的值为9.81 m/S 2。
因为排除各个轴的重力影响是相当普遍的需要,因此Android 2.3(API level 9)也支持线性加速传感器及重力传感器,本章后面将探讨。
陀螺仪
陀螺仪衡量角速度或围绕3条轴的旋转速度。所有值的单位都是弧度/秒。旋转值沿逆时针方向是正值。也就是说,当一个人正常查看设备屏幕时(在设备的0,0,100坐标),如果设备看起来是逆时针旋转时,则其旋转值为正值。因为旋转速度是个角速度,要计算角度,必须整合一段时间的旋转值:
private static final float NS2S = 1.0f / 1000000000.0f;private float timestamp;private float angle;@Overridepublic void onSensorChanged(SensorEvent event) { float gyrox = event.values[0]; float gyroy = event.values[1]; float gyroz = event.values[2]; // here we integrate over time to figure out the rotational angle around each axis if (timestamp != 0) { final float dT = (event.timestamp - timestamp) * NS2S; angle[0] += gyrox * dT; angle[1] += gyroy * dT; angle[2] += gyroz * dT; } timestamp = event.timestamp;}
由于这是一种常见情况,故Android 2.3(API level 9)也支持旋转向量传感器,我们将在下一节探讨它。
旋转向量
在Android 2.3及更高的版本中,旋转向量表示设备的方向,其以角度和轴的组合形式表示,即设备沿着轴<x,y,z>旋转角度Θ。虽然可以通过陀螺仪计算旋转角度,但很多开发人员觉得该计算太烦琐了,因而Google提供了旋转向量来简化使用方式。
旋转向量的3个元素分别是x*sin(Θ/2),y*sin(Θ/2)和z*sin(Θ/2),因此旋转向量的矢量值为sin(Θ/2),旋转向量的方向就相当于旋转轴的方向。旋转向量的3个元素相当于单位4元素<cos(Θ/2),x*sin(Θ/2),y*sin(Θ/2)和z*sin(Θ/2)>的最后3个元素。旋转向量的元素是无单位的。
线性加速
Android 2.3(API level 9)支持的另一种简化了常用计算的传感器类型是加速度计。发送的加速度值是个三维向量,是沿着每个设备轴的加速度,已经排除了重力。这意味着其值是每条轴上的线性加速度减去重力在该轴上导致的线性加速度。这使得对于在地球上使用手机,更易于排除重力的常数影响。所有加速度值的单位都是m/S 2。
重力
传感器的三维矢量表示重力的方向和幅度。Android 2.3(API level 9)传感器提供了它的计算方式,其单位是m/S 2。
其他传感器
Android还支持以下传感器:
光
该传感器提供单一值的数组(value[0]),它检测的是环境中的光的级别,单位是SI lux(lx)。
磁
该传感器检测环境中x轴、y轴和z轴的磁场,单位是microteslas(T)。
压力
提供该传感器的设备不多,其值单位是千帕斯卡(kPa)。
距离
该传感器提供单一值的数组(value[0]),表示到传感器的距离,单位是厘米(cm)。在某些情况下,proximity传感器可能只提供二进制形式的near(0)值和far(1)值。在这种情况下,大于等于传感器的getMaximumRange方法所返回的值将返回far,反之则返回near。
温度
提供该传感器的设备也不多。其单位是摄氏度()。
周围环境温度
能够识别周围环境温度的传感器的设备不多,其数值单位是摄氏度()。在Android 4.0(API Level 14)以及更新版本中支持。
相对湿度
能够识别相对湿度的传感器的设备不多,其数值是百分比(%)表示。在Android 4.0(API Level 14)以及更新版本中支持。