转载:http://dev.10086.cn/cmdn/bbs/thread-41843-1-1.html
1、传感器入门
自从苹果公司在2007年发布第一代iPhone以来,以前看似和手机挨不着边的传感器也逐渐成为手机硬件的重要组成部分。如果读者使用过iPhone、HTC Dream、HTC Magic、HTC Hero以及其他的Android手机,会发现通过将手机横向或纵向放置,屏幕会随着手机位置的不同而改变方向。这种功能就需要通过重力传感器来实现,除了重力传感器,还有很多其他类型的传感器被应用到手机中,例如磁阻传感器就是最重要的一种传感器。虽然手机可以通过GPS来判断方向,但在GPS信号不好或根本没有GPS信号的情况下,GPS就形同虚设。这时通过磁阻传感器就可以很容易判断方向(东、南、西、北)。有了磁阻传感器,也使罗盘(俗称指向针)的电子化成为可能。
在Android应用程序中使用传感器要依赖于android.hardware.SensorEventListener接口。通过该接口可以监听传感器的各种事件。SensorEventListener接口的代码如下:
- package android.hardware;
-
- public interface SensorEventListener
-
- {
-
- public void onSensorChanged(SensorEvent event);
-
- public void onAccuracyChanged(Sensor sensor, int accuracy);
-
- }
在SensorEventListener接口中定义了两个方法:onSensorChanged和onAccuracyChanged。当传感器的值发生变化时,例如磁阻传感器的方向改变时会调用onSensorChanged方法。当传感器的精度变化时会调用onAccuracyChanged方法。
onSensorChanged方法只有一个SensorEvent类型的参数event,其中SensorEvent类有一个values变量非常重要,该变量的类型是float[]。但该变量最多只有3个元素,而且根据传感器的不同,values变量中元素所代表的含义也不同。
在解释values变量中元素的含义之前,先来介绍一下Android的坐标系统是如何定义X、Y、Z轴的。
X轴的方向是沿着屏幕的水平方向从左向右。如果手机不是正方形的话,较短的边需要水平放置,较长的边需要垂直放置。
Y轴的方向是从屏幕的左下角开始沿着屏幕的垂直方向指向屏幕的顶端。
将手机平放在桌子上,Z轴的方向是从手机里指向天空。
下面是values变量的元素在主要的传感器中所代表的含义。
1.1方向传感器
在方向传感器中values变量的3个值都表示度数,它们的含义如下:
values[0]:该值表示方位,也就是手机绕着Z轴旋转的角度。0表示北(North);90表示东(East);180表示南(South);270表示西(West)。如果values[0]的值正好是这4个值,并且手机是水平放置,表示手机的正前方就是这4个方向。可以利用这个特性来实现电子罗盘,实例76将详细介绍电子罗盘的实现过程。
values[1]:该值表示倾斜度,或手机翘起的程度。当手机绕着X轴倾斜时该值发生变化。values[1]的取值范围是-180≤values[1]
≤180。假设将手机屏幕朝上水平放在桌子上,这时如果桌子是完全水平的,values[1]的值应该是0(由于很少有桌子是绝对水平的,因此,该值很可能不为0,但一般都是-5和5之间的某个值)。这时从手机顶部开始抬起,直到将手机沿X轴旋转180度(屏幕向下水平放在桌面上)。在这个旋转过程中,values[1]会在0到-180之间变化,也就是说,从手机顶部抬起时,values[1]的值会逐渐变小,直到等于-180。如果从手机底部开始抬起,直到将手机沿X轴旋转180度,这时values[1]会在0到180之间变化。也就是values[1]的值会逐渐增大,直到等于180。可以利用values[1]和下面要介绍的values[2]来测量桌子等物体的倾斜度。
values[2]:表示手机沿着Y轴的滚动角度。取值范围是-90≤values[2]≤90。假设将手机屏幕朝上水平放在桌面上,这时如果桌面是平的,values[2]的值应为0。将手机左侧逐渐抬起时,values[2]的值逐渐变小,直到手机垂直于桌面放置,这时values[2]的值是-90。将手机右侧逐渐抬起时,values[2]的值逐渐增大,直到手机垂直于桌面放置,这时values[2]的值是90。在垂直位置时继续向右或向左滚动,values[2]的值会继续在-90至90之间变化。
1.2加速传感器
该传感器的values变量的3个元素值分别表示X、Y、Z轴的加速值。例如,水平放在桌面上的手机从左侧向右侧移动,values[0]为负值;从右向左移动,values[0]为正值。读者可以通过本节的例子来体会加速传感器中的值的变化。要想使用相应的传感器,仅实现SensorEventListener接口是不够的,还需要使用下面的代码来注册相应的传感器。
- // 获得传感器管理器
-
- SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
-
- // 注册方向传感器
-
- sm.registerListener(this,
-
- sm.getDefaultSensor(Sensor.TYPE_ORIENTATION),
-
- SensorManager.SENSOR_DELAY_FASTEST);
如果想注册其他的传感器,可以改变getDefaultSensor方法的第1个参数值,例如,注册加速传感器可以使用Sensor.TYPE_ACCELEROMETER。在Sensor类中还定义了很多传感器常量,但要根据手机中实际的硬件配置来注册传感器。如果手机中没有相应的传感器硬件,就算注册了相应的传感器也不起任何作用。getDefaultSensor方法的第2个参数表示获得传感器数据的速度。SensorManager.SENSOR_DELAY_ FASTEST表示尽可能快地获得传感器数据。除了该值以外,还可以设置3个获得传感器数据的速度值,这些值如下:
SensorManager.SENSOR_DELAY_NORMAL:默认的获得传感器数据的速度。
SensorManager.SENSOR_DELAY_GAME:如果利用传感器开发游戏,建议使用该值。
SensorManager.SENSOR_DELAY_UI:如果使用传感器更新UI中的数据,建议使用该值。
1.5陀螺仪传感器
陀螺仪传感器的类型常量是Sensor.TYPE_GYROSCOPE。values数组的三个元素表示的含义如下:values[0]:延X轴旋转的角速度。
values[1]:延Y轴旋转的角速度。
values[2]:延Z轴旋转的角速度。
当手机逆时针旋转时,角速度为正值,顺时针旋转时,角速度为负值。陀螺仪传感器经常被用来计算手机已转动的角度,代码如下:private static final float NS2S = 1.0f / 1000000000.0f;
- private float timestamp;
-
- public void onSensorChanged(SensorEvent event)
-
- {
-
- if (timestamp != 0)
-
- {
-
- // event.timesamp表示当前的时间,单位是纳秒(1百万分之一毫秒)
-
- final float dT = (event.timestamp - timestamp) * NS2S;
-
- angle[0] += event.values[0] * dT;
-
- angle[1] += event.values[1] * dT;
-
- angle[2] += event.values[2] * dT;
-
- }
-
- timestamp = event.timestamp;
-
- }
上面代码中通过陀螺仪传感器相邻两次获得数据的时间差(dT)来分别计算在这段时间内手机延X、 Y、Z轴旋转的角度,并将值分别累加到angle数组的不同元素上。
1.6其他传感器
其他传感器在前面几节介绍了加速度传感器、重力传感器、光线传感器、陀螺仪传感器以及方向传感器。除了这些传感器外,Android SDK还支持如下的几种传感器。关于这些传感器的使用方法以及与这些传感器相关的常量、方法,读者可以参阅官方文档。
近程传感器(Sensor.TYPE_PROXIMITY)
线性加速度传感器(Sensor.TYPE_LINEAR_ACCELERATION)
旋转向量传感器(Sensor.TYPE_ROTATION_VECTOR)
磁场传感器(Sensor.TYPE_MAGNETIC_FIELD)
压力传感器(Sensor.TYPE_PRESSURE)
温度传感器(Sensor.TYPE_TEMPERATURE)
虽然AndroidSDK定义了十多种传感器,但并不是每一部手机都完全支持这些传感器。例如,Google Nexus S支持其中的9种传感器(不支持压力和温度传感器),而HTC G7只支持其中的5种传感器。如果使用了手机不支持的传感器,一般不会抛出异常,但也无法获得传感器传回的数据。读者在使用传感器时最好先判断当前的手机是否支持所使用的传感器。
2. 测试手机中有哪些传感器(作者:银河使者)
我们可以通过如下三步使用传感器。
(1)编写一个截获传感器事件的类。该类必须实现android.hardware.SensorEventListener接口。
(2)获得传感器管理对象(SensorManager对象)。
(3)使用SensorManager.registerListener方法注册指定的传感器。
通过上面三步已经搭建了传感器应用程序的框架。而具体的工作需要在SensorEventListener接口的onSensorChanged和onAccuracyChanged方法中完成。SensorEventListener接口的定义如下:packageandroid.hardware;
- public interfaceSensorEventListener
-
- {
-
- //传感器数据变化时调用
-
- public void onSensorChanged(SensorEventevent);
-
- //传感器精确度变化时调用
-
- public void onAccuracyChanged(Sensorsensor, int accuracy);
-
- }
SensorManager对象通过getSystemService方法获得,代码如下:SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
复制代码通常手机中包含了若干个传感器模块(如方向传感器、光线传感器等),因此,注册传感器需要指定传感器的类型,如下面的代码注册了光线传感器。
- sensorManager.registerListener(this,sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
-
- SensorManager.SENSOR_DELAY_FASTEST);
registerListener方法有三个参数。第1个参数是实现SensorEventListener接口的对象。第2个参数用于指定传感器的类型。AndroidSDK预先定义了表示各种传感器的常量,这些常量都被放在Sensor类中。例如,上面代码中的Sensor.TYPE_LIGHT。第3个参数表示传感器获得数据的速度。该参数可设置的常量如下:
SENSOR_DELAY_FASTEST:以最快的速度获得传感器数据。
SENSOR_DELAY_GAME:适合于在游戏中获得传感器数据。
SENSOR_DELAY_UI:适合于在UI控件中获得传感器数据。
SENSOR_DELAY_NORMAL:以一般的速度获得传感器的数据。
上面四种类型获得传感器数据的速度依次递减。从理论上说,获得传感器数据的速度越快,消耗的系统资源越大。因此建议读者根本实际情况选择适当的速度获得传感器的数据。
如果想停止获得传感器数据,可以使用unregisterSensor方法注销传感器事件对象。
- unregisterSensor方法的定义如下:
- public voidunregisterListener(SensorEventListener listener)
-
- public voidunregisterListener(SensorEventListener listener, Sensor sensor)
unregisterSensor方法有两个重载形式。第一个重载形式用于注销所有的传感器对象。第二个重载形式用于注销指定传感器的事件对象。其中Sensor对象通过SensorManager.getDefaultSensor方法获得。getDefaultSensor方法只有一个int类型的参数,表示传感器的类型。如Sensor.TYPE_LIGHT表示光线传感器。
注意:一个传感器对像可以处理多个传感器。也就是说,一个实现SensorEventListener接口的类可以接收多个传感器传回的数据。为了区分不同的传感器,需要使用Sensor.getType方法来获得传感器的类型。getType方法的将在本节的例子中详细介绍。
通过SensorManager.getSensorList方法可以获得指定传感器的信息,也可以获得手机支持的所有传感器的信息,代码如下
- //获得光线传感器
-
- List<Sensor>sensors = sensorManager.getSensorList(Sensor.TYPE_LIGHT);
-
- //获得手机支持的所有传感器
-
- List<Sensor>sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
下面给出一个完整的例子来演示如何获得传感器传回的数据。本例从如下4个传感器获得数据,同时输出了测试手机中支持的所有传感器名称。
加速度传感器(Sensor.TYPE_ACCELEROMETER)
磁场传感器(Sensor.TYPE_MAGNETIC_FIELD)
光线传感器(Sensor.TYPE_LIGHT)
方向传感器(TYPE_ORIENTATION)
本例需要在真机上运行。由于不同的手机可能支持的传感器不同(有的手机并不支持Android SDK中定义的所有传感器),因此,如果运行程序后,无法显示某个传感器的数据,说明当前的手机并不支持这个传感器。笔者已使用Google Nexus S测试了本例。如果读者使用的也是GoogleNexus S,则会输出如图1类似的信息。
本例的完整代码如下:
- package mobile.android. sensor;
-
- import java.util.List;
- import android.app.Activity;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.widget.TextView;
-
- public class Main extends Activity implements SensorEventListener
- {
- private TextView tvAccelerometer;
- private TextView tvMagentic;
- private TextView tvLight;
- private TextView tvOrientation;
- private TextView tvSensors;
-
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- // 获得SensorManager对象
- SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
-
- // 注册加速度传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
- SensorManager.SENSOR_DELAY_FASTEST);
-
- // 注册磁场传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
- SensorManager.SENSOR_DELAY_FASTEST);
-
- // 注册光线传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
- SensorManager.SENSOR_DELAY_FASTEST);
-
- // 注册方向传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
- SensorManager.SENSOR_DELAY_FASTEST);
-
- tvAccelerometer = (TextView) findViewById(R.id.tvAccelerometer);
- tvMagentic = (TextView) findViewById(R.id.tvMagentic);
- tvLight = (TextView) findViewById(R.id.tvLight);
- tvOrientation = (TextView) findViewById(R.id.tvOrientation);
- tvSensors = (TextView)findViewById(R.id.tvSensors);
-
- // 获得当前手机支持的所有传感器
- List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
- for(Sensor sensor:sensors)
- {
- // 输出当前传感器的名称
- tvSensors.append(sensor.getName() + "\n");
- }
- }
- @Override
- public void onSensorChanged(SensorEvent event)
- {
- // 通过getType方法获得当前传回数据的传感器类型
- switch (event.sensor.getType())
- {
- case Sensor.TYPE_ACCELEROMETER: // 处理加速度传感器传回的数据
- String accelerometer = "加速度\n" + "X:" + event.values[0] + "\n"
- + "Y:" + event.values[1] + "\n" + "Z:" + event.values[2] + "\n";
- tvAccelerometer.setText(accelerometer);
- break;
- case Sensor.TYPE_LIGHT: // 处理光线传感器传回的数据
- tvLight.setText("亮度:" + event.values[0]);
- break;
- case Sensor.TYPE_MAGNETIC_FIELD: // 处理磁场传感器传回的数据
- String magentic = "磁场\n" + "X:" + event.values[0] + "\n" + "Y:"
- + event.values[1] + "\n" + "Z:" + event.values[2] + "\n";
- tvMagentic.setText(magentic);
- break;
- case Sensor.TYPE_ORIENTATION: // 处理方向传感器传回的数据
- String orientation = "方向\n" + "X:" + event.values[0] + "\n"
- + "Y:" + event.values[1] + "\n" + "Z:" + event.values[2] + "\n";
- tvOrientation.setText(orientation);
- break;
- }
- }
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy)
- {
- }
- }
3.1电子罗盘
电子罗盘又叫电子指南针。在实现本例之前,先看一下如图1所示的运行效果。
图1 电子罗盘
其中N、S、W和E分别表示北、南、西和东4个方向。
本例只使用了onSensorChanged事件方法及values[0]。由于指南针图像上方是北,当手机前方是正北时(values[0]=0),图像不需要旋转。但如果不是正北,就需要将图像按一定角度旋转。假设当前values[0]的值是60,说明方向在东北方向。也就是说,手机顶部由北向东旋转。这时如果图像不旋转,N的方向正好和正北的夹角是60度,需要将图像逆时针(从东向北旋转)旋转60度,N才会指向正北方。因此,可以使用在11.2.3节介绍的旋转补间动画来旋转指南针图像,代码如下:
- public void onSensorChanged(SensorEvent event)
-
- {
-
- if (event.sensor.getType() == Sensor.TYPE_ORIENTATION)
-
- {
-
- float degree = event.values[0];
-
- // 以指南针图像中心为轴逆时针旋转degree度
-
- RotateAnimation ra = new RotateAnimation(currentDegree, -degree,
-
- Animation.RELATIVE_TO_SELF, 0.5f,
-
- Animation.RELATIVE_TO_SELF, 0.5f);
-
- // 在200毫秒之内完成旋转动作
-
- ra.setDuration(200);
-
- // 开始旋转图像
-
- imageView.startAnimation(ra);
-
- // 保存旋转后的度数,currentDegree是一个在类中定义的float类型变量
-
- currentDegree = -degree;
-
- }
-
- }
上面的代码中使用了event.values数组中的数据来获得传感器传回的数据。这个values数组非常重要,它的长度为3。但不一定每一个数组元素都有意义。对于不同的传感器,每个数组元素的含义不同。在下面的部分将详细介绍不同传感器中values数组各个元素的含义。
注意:虽然使用Sensor.TYPE_ALL可以获得手机支持的所有传感器信息,但不能使用Sensor.TYPE_ALL注册所有的传感器,也就是getDefaultSensor方法的参数值必须是某个传感器的类型常量,而不能是Sensor.TYPE_ALL。
1、传感器入门
自从苹果公司在2007年发布第一代iPhone以来,以前看似和手机挨不着边的传感器也逐渐成为手机硬件的重要组成部分。如果读者使用过iPhone、HTC Dream、HTC Magic、HTC Hero以及其他的Android手机,会发现通过将手机横向或纵向放置,屏幕会随着手机位置的不同而改变方向。这种功能就需要通过重力传感器来实现,除了重力传感器,还有很多其他类型的传感器被应用到手机中,例如磁阻传感器就是最重要的一种传感器。虽然手机可以通过GPS来判断方向,但在GPS信号不好或根本没有GPS信号的情况下,GPS就形同虚设。这时通过磁阻传感器就可以很容易判断方向(东、南、西、北)。有了磁阻传感器,也使罗盘(俗称指向针)的电子化成为可能。
在Android应用程序中使用传感器要依赖于android.hardware.SensorEventListener接口。通过该接口可以监听传感器的各种事件。SensorEventListener接口的代码如下:
- package android.hardware;
- public interface SensorEventListener
- {
- public void onSensorChanged(SensorEvent event);
- public void onAccuracyChanged(Sensor sensor, int accuracy);
- }
在SensorEventListener接口中定义了两个方法:onSensorChanged和onAccuracyChanged。当传感器的值发生变化时,例如磁阻传感器的方向改变时会调用onSensorChanged方法。当传感器的精度变化时会调用onAccuracyChanged方法。
onSensorChanged方法只有一个SensorEvent类型的参数event,其中SensorEvent类有一个values变量非常重要,该变量的类型是float[]。但该变量最多只有3个元素,而且根据传感器的不同,values变量中元素所代表的含义也不同。
在解释values变量中元素的含义之前,先来介绍一下Android的坐标系统是如何定义X、Y、Z轴的。
X轴的方向是沿着屏幕的水平方向从左向右。如果手机不是正方形的话,较短的边需要水平放置,较长的边需要垂直放置。
Y轴的方向是从屏幕的左下角开始沿着屏幕的垂直方向指向屏幕的顶端。
将手机平放在桌子上,Z轴的方向是从手机里指向天空。
下面是values变量的元素在主要的传感器中所代表的含义。
1.1方向传感器
在方向传感器中values变量的3个值都表示度数,它们的含义如下:
values[0]:该值表示方位,也就是手机绕着Z轴旋转的角度。0表示北(North);90表示东(East);180表示南(South);270表示西(West)。如果values[0]的值正好是这4个值,并且手机是水平放置,表示手机的正前方就是这4个方向。可以利用这个特性来实现电子罗盘,实例76将详细介绍电子罗盘的实现过程。
values[1]:该值表示倾斜度,或手机翘起的程度。当手机绕着X轴倾斜时该值发生变化。values[1]的取值范围是-180≤values[1]
≤180。假设将手机屏幕朝上水平放在桌子上,这时如果桌子是完全水平的,values[1]的值应该是0(由于很少有桌子是绝对水平的,因此,该值很可能不为0,但一般都是-5和5之间的某个值)。这时从手机顶部开始抬起,直到将手机沿X轴旋转180度(屏幕向下水平放在桌面上)。在这个旋转过程中,values[1]会在0到-180之间变化,也就是说,从手机顶部抬起时,values[1]的值会逐渐变小,直到等于-180。如果从手机底部开始抬起,直到将手机沿X轴旋转180度,这时values[1]会在0到180之间变化。也就是values[1]的值会逐渐增大,直到等于180。可以利用values[1]和下面要介绍的values[2]来测量桌子等物体的倾斜度。
values[2]:表示手机沿着Y轴的滚动角度。取值范围是-90≤values[2]≤90。假设将手机屏幕朝上水平放在桌面上,这时如果桌面是平的,values[2]的值应为0。将手机左侧逐渐抬起时,values[2]的值逐渐变小,直到手机垂直于桌面放置,这时values[2]的值是-90。将手机右侧逐渐抬起时,values[2]的值逐渐增大,直到手机垂直于桌面放置,这时values[2]的值是90。在垂直位置时继续向右或向左滚动,values[2]的值会继续在-90至90之间变化。
1.2加速传感器
该传感器的values变量的3个元素值分别表示X、Y、Z轴的加速值。例如,水平放在桌面上的手机从左侧向右侧移动,values[0]为负值;从右向左移动,values[0]为正值。读者可以通过本节的例子来体会加速传感器中的值的变化。要想使用相应的传感器,仅实现SensorEventListener接口是不够的,还需要使用下面的代码来注册相应的传感器。
- // 获得传感器管理器
- SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);
- // 注册方向传感器
- sm.registerListener(this,
- sm.getDefaultSensor(Sensor.TYPE_ORIENTATION),
- SensorManager.SENSOR_DELAY_FASTEST);
如果想注册其他的传感器,可以改变getDefaultSensor方法的第1个参数值,例如,注册加速传感器可以使用Sensor.TYPE_ACCELEROMETER。在Sensor类中还定义了很多传感器常量,但要根据手机中实际的硬件配置来注册传感器。如果手机中没有相应的传感器硬件,就算注册了相应的传感器也不起任何作用。getDefaultSensor方法的第2个参数表示获得传感器数据的速度。SensorManager.SENSOR_DELAY_ FASTEST表示尽可能快地获得传感器数据。除了该值以外,还可以设置3个获得传感器数据的速度值,这些值如下:
SensorManager.SENSOR_DELAY_NORMAL:默认的获得传感器数据的速度。
SensorManager.SENSOR_DELAY_GAME:如果利用传感器开发游戏,建议使用该值。
SensorManager.SENSOR_DELAY_UI:如果使用传感器更新UI中的数据,建议使用该值。
1.5陀螺仪传感器
陀螺仪传感器的类型常量是Sensor.TYPE_GYROSCOPE。values数组的三个元素表示的含义如下:values[0]:延X轴旋转的角速度。
values[1]:延Y轴旋转的角速度。
values[2]:延Z轴旋转的角速度。
当手机逆时针旋转时,角速度为正值,顺时针旋转时,角速度为负值。陀螺仪传感器经常被用来计算手机已转动的角度,代码如下:private static final float NS2S = 1.0f / 1000000000.0f;
- private float timestamp;
- public void onSensorChanged(SensorEvent event)
- {
- if (timestamp != 0)
- {
- // event.timesamp表示当前的时间,单位是纳秒(1百万分之一毫秒)
- final float dT = (event.timestamp - timestamp) * NS2S;
- angle[0] += event.values[0] * dT;
- angle[1] += event.values[1] * dT;
- angle[2] += event.values[2] * dT;
- }
- timestamp = event.timestamp;
- }
上面代码中通过陀螺仪传感器相邻两次获得数据的时间差(dT)来分别计算在这段时间内手机延X、 Y、Z轴旋转的角度,并将值分别累加到angle数组的不同元素上。
1.6其他传感器
其他传感器在前面几节介绍了加速度传感器、重力传感器、光线传感器、陀螺仪传感器以及方向传感器。除了这些传感器外,Android SDK还支持如下的几种传感器。关于这些传感器的使用方法以及与这些传感器相关的常量、方法,读者可以参阅官方文档。
近程传感器(Sensor.TYPE_PROXIMITY)
线性加速度传感器(Sensor.TYPE_LINEAR_ACCELERATION)
旋转向量传感器(Sensor.TYPE_ROTATION_VECTOR)
磁场传感器(Sensor.TYPE_MAGNETIC_FIELD)
压力传感器(Sensor.TYPE_PRESSURE)
温度传感器(Sensor.TYPE_TEMPERATURE)
虽然AndroidSDK定义了十多种传感器,但并不是每一部手机都完全支持这些传感器。例如,Google Nexus S支持其中的9种传感器(不支持压力和温度传感器),而HTC G7只支持其中的5种传感器。如果使用了手机不支持的传感器,一般不会抛出异常,但也无法获得传感器传回的数据。读者在使用传感器时最好先判断当前的手机是否支持所使用的传感器。
2. 测试手机中有哪些传感器(作者:银河使者)
我们可以通过如下三步使用传感器。
(1)编写一个截获传感器事件的类。该类必须实现android.hardware.SensorEventListener接口。
(2)获得传感器管理对象(SensorManager对象)。
(3)使用SensorManager.registerListener方法注册指定的传感器。
通过上面三步已经搭建了传感器应用程序的框架。而具体的工作需要在SensorEventListener接口的onSensorChanged和onAccuracyChanged方法中完成。SensorEventListener接口的定义如下:packageandroid.hardware;
- public interfaceSensorEventListener
- {
- //传感器数据变化时调用
- public void onSensorChanged(SensorEventevent);
- //传感器精确度变化时调用
- public void onAccuracyChanged(Sensorsensor, int accuracy);
- }
SensorManager对象通过getSystemService方法获得,代码如下:SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
复制代码通常手机中包含了若干个传感器模块(如方向传感器、光线传感器等),因此,注册传感器需要指定传感器的类型,如下面的代码注册了光线传感器。
- sensorManager.registerListener(this,sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
- SensorManager.SENSOR_DELAY_FASTEST);
registerListener方法有三个参数。第1个参数是实现SensorEventListener接口的对象。第2个参数用于指定传感器的类型。AndroidSDK预先定义了表示各种传感器的常量,这些常量都被放在Sensor类中。例如,上面代码中的Sensor.TYPE_LIGHT。第3个参数表示传感器获得数据的速度。该参数可设置的常量如下:
SENSOR_DELAY_FASTEST:以最快的速度获得传感器数据。
SENSOR_DELAY_GAME:适合于在游戏中获得传感器数据。
SENSOR_DELAY_UI:适合于在UI控件中获得传感器数据。
SENSOR_DELAY_NORMAL:以一般的速度获得传感器的数据。
上面四种类型获得传感器数据的速度依次递减。从理论上说,获得传感器数据的速度越快,消耗的系统资源越大。因此建议读者根本实际情况选择适当的速度获得传感器的数据。
如果想停止获得传感器数据,可以使用unregisterSensor方法注销传感器事件对象。
- unregisterSensor方法的定义如下:
- public voidunregisterListener(SensorEventListener listener)
- public voidunregisterListener(SensorEventListener listener, Sensor sensor)
unregisterSensor方法有两个重载形式。第一个重载形式用于注销所有的传感器对象。第二个重载形式用于注销指定传感器的事件对象。其中Sensor对象通过SensorManager.getDefaultSensor方法获得。getDefaultSensor方法只有一个int类型的参数,表示传感器的类型。如Sensor.TYPE_LIGHT表示光线传感器。
注意:一个传感器对像可以处理多个传感器。也就是说,一个实现SensorEventListener接口的类可以接收多个传感器传回的数据。为了区分不同的传感器,需要使用Sensor.getType方法来获得传感器的类型。getType方法的将在本节的例子中详细介绍。
通过SensorManager.getSensorList方法可以获得指定传感器的信息,也可以获得手机支持的所有传感器的信息,代码如下
- //获得光线传感器
- List<Sensor>sensors = sensorManager.getSensorList(Sensor.TYPE_LIGHT);
- //获得手机支持的所有传感器
- List<Sensor>sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
下面给出一个完整的例子来演示如何获得传感器传回的数据。本例从如下4个传感器获得数据,同时输出了测试手机中支持的所有传感器名称。
加速度传感器(Sensor.TYPE_ACCELEROMETER)
磁场传感器(Sensor.TYPE_MAGNETIC_FIELD)
光线传感器(Sensor.TYPE_LIGHT)
方向传感器(TYPE_ORIENTATION)
本例需要在真机上运行。由于不同的手机可能支持的传感器不同(有的手机并不支持Android SDK中定义的所有传感器),因此,如果运行程序后,无法显示某个传感器的数据,说明当前的手机并不支持这个传感器。笔者已使用Google Nexus S测试了本例。如果读者使用的也是GoogleNexus S,则会输出如图1类似的信息。
本例的完整代码如下:
- package mobile.android. sensor;
- import java.util.List;
- import android.app.Activity;
- import android.hardware.Sensor;
- import android.hardware.SensorEvent;
- import android.hardware.SensorEventListener;
- import android.hardware.SensorManager;
- import android.os.Bundle;
- import android.widget.TextView;
- public class Main extends Activity implements SensorEventListener
- {
- private TextView tvAccelerometer;
- private TextView tvMagentic;
- private TextView tvLight;
- private TextView tvOrientation;
- private TextView tvSensors;
- @Override
- public void onCreate(Bundle savedInstanceState)
- {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- // 获得SensorManager对象
- SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
- // 注册加速度传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
- SensorManager.SENSOR_DELAY_FASTEST);
- // 注册磁场传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
- SensorManager.SENSOR_DELAY_FASTEST);
- // 注册光线传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
- SensorManager.SENSOR_DELAY_FASTEST);
- // 注册方向传感器
- sensorManager.registerListener(this,
- sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
- SensorManager.SENSOR_DELAY_FASTEST);
- tvAccelerometer = (TextView) findViewById(R.id.tvAccelerometer);
- tvMagentic = (TextView) findViewById(R.id.tvMagentic);
- tvLight = (TextView) findViewById(R.id.tvLight);
- tvOrientation = (TextView) findViewById(R.id.tvOrientation);
- tvSensors = (TextView)findViewById(R.id.tvSensors);
- // 获得当前手机支持的所有传感器
- List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
- for(Sensor sensor:sensors)
- {
- // 输出当前传感器的名称
- tvSensors.append(sensor.getName() + "\n");
- }
- }
- @Override
- public void onSensorChanged(SensorEvent event)
- {
- // 通过getType方法获得当前传回数据的传感器类型
- switch (event.sensor.getType())
- {
- case Sensor.TYPE_ACCELEROMETER: // 处理加速度传感器传回的数据
- String accelerometer = "加速度\n" + "X:" + event.values[0] + "\n"
- + "Y:" + event.values[1] + "\n" + "Z:" + event.values[2] + "\n";
- tvAccelerometer.setText(accelerometer);
- break;
- case Sensor.TYPE_LIGHT: // 处理光线传感器传回的数据
- tvLight.setText("亮度:" + event.values[0]);
- break;
- case Sensor.TYPE_MAGNETIC_FIELD: // 处理磁场传感器传回的数据
- String magentic = "磁场\n" + "X:" + event.values[0] + "\n" + "Y:"
- + event.values[1] + "\n" + "Z:" + event.values[2] + "\n";
- tvMagentic.setText(magentic);
- break;
- case Sensor.TYPE_ORIENTATION: // 处理方向传感器传回的数据
- String orientation = "方向\n" + "X:" + event.values[0] + "\n"
- + "Y:" + event.values[1] + "\n" + "Z:" + event.values[2] + "\n";
- tvOrientation.setText(orientation);
- break;
- }
- }
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy)
- {
- }
- }
3.1电子罗盘
电子罗盘又叫电子指南针。在实现本例之前,先看一下如图1所示的运行效果。
图1 电子罗盘
其中N、S、W和E分别表示北、南、西和东4个方向。
本例只使用了onSensorChanged事件方法及values[0]。由于指南针图像上方是北,当手机前方是正北时(values[0]=0),图像不需要旋转。但如果不是正北,就需要将图像按一定角度旋转。假设当前values[0]的值是60,说明方向在东北方向。也就是说,手机顶部由北向东旋转。这时如果图像不旋转,N的方向正好和正北的夹角是60度,需要将图像逆时针(从东向北旋转)旋转60度,N才会指向正北方。因此,可以使用在11.2.3节介绍的旋转补间动画来旋转指南针图像,代码如下:
- public void onSensorChanged(SensorEvent event)
- {
- if (event.sensor.getType() == Sensor.TYPE_ORIENTATION)
- {
- float degree = event.values[0];
- // 以指南针图像中心为轴逆时针旋转degree度
- RotateAnimation ra = new RotateAnimation(currentDegree, -degree,
- Animation.RELATIVE_TO_SELF, 0.5f,
- Animation.RELATIVE_TO_SELF, 0.5f);
- // 在200毫秒之内完成旋转动作
- ra.setDuration(200);
- // 开始旋转图像
- imageView.startAnimation(ra);
- // 保存旋转后的度数,currentDegree是一个在类中定义的float类型变量
- currentDegree = -degree;
- }
- }
上面的代码中使用了event.values数组中的数据来获得传感器传回的数据。这个values数组非常重要,它的长度为3。但不一定每一个数组元素都有意义。对于不同的传感器,每个数组元素的含义不同。在下面的部分将详细介绍不同传感器中values数组各个元素的含义。
注意:虽然使用Sensor.TYPE_ALL可以获得手机支持的所有传感器信息,但不能使用Sensor.TYPE_ALL注册所有的传感器,也就是getDefaultSensor方法的参数值必须是某个传感器的类型常量,而不能是Sensor.TYPE_ALL。