Android的传感器开发
1.1 开发传感器应用
开发传感器的步骤如下:
调用Context的getSystemService(Context.SENSOR_SERVICE)方法获取SensorManager对象。
调用SensorManager的getDefaultSensor(int type)方法来获取指定类型的传感器。
一般在Activity的onResume()方法中调用SensorManager的registerListener()为指定传感器注册监听器即可。程序可以通过实现监听器即可获取传感器传回来的数据。
SersorManager提供的注册传感器的方法为registerListener(SensorListener listener, Sensor sensor, int rate)该方法中三个参数说明如下:
listener:监听传感器事件的监听器
sensor:传感器对象
rate:指定获取传感器数据的频率
rate可以获取传感器数据的频率,支持如下几个频率值:
SENSOR_DELAY_FASTEST:最快,延迟最小。
SENSOR_DELAY_GAME:适合游戏的频率。
SENSOR_DELAY_NORMAL:正常频率
SENSOR_DELAY_UI:适合普通用户界面的频率。
例:加速度传感器:
AccelerometerTest.java
public class AccelerometerTest extends Activity
implements SensorEventListener
{
// 定义系统的Sensor管理器
SensorManager sensorManager;
EditText etTxt1;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取程序界面上的文本框组件
etTxt1 = (EditText) findViewById(R.id.txt1);
// 获取系统的传感器管理服务
sensorManager = (SensorManager) getSystemService(
Context.SENSOR_SERVICE);
}
@Override
protected void onResume()
{
super.onResume();
// 为系统的加速度传感器注册监听器
sensorManager.registerListener(this,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
// 取消注册
sensorManager.unregisterListener(this);
super.onStop();
}
// 以下是实现SensorEventListener接口必须实现的方法
// 当传感器的值发生改变时回调该方法
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
StringBuilder sb = new StringBuilder();
sb.append(X方向上的加速度:);
sb.append(values[0]);
sb.append(
Y方向上的加速度:);
sb.append(values[1]);
sb.append(
Z方向上的加速度:);
sb.append(values[2]);
etTxt1.setText(sb.toString());
}
// 当传感器精度改变时回调该方法。
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
需要指出的是,传感器的坐标系统与屏幕坐标系统不同,传感器坐标系统的X轴沿屏幕向右;Y轴则沿屏幕向上,Z轴在垂直屏幕向上。
当拿着手机横向左右移动时,可能产生X轴上的加速度;拿着手机前后移动时,可能产生Y轴上的加速度;当拿着手机竖向上下移动时,可能产生Z轴上的加速度。
1.2 下载和安装SensorSimulator
SensorSimulator是传感器的模拟工具,安装这个模拟工具之后,开发者就可以在Android模拟器上开发、调试传感器应用。
SensorSimulator,由PC端程序和手机端程序组成,当两端的程序运行并建立连接之后,用户可以通过PC端的程序来改变手机的传感数据。
下载和安装SensorSimulator步骤如下:
登录到http://code.google.com/p/openintents/wiki/SensorSimulator站点或FTP上,下载SensorSimulator的最新版本。
下载SensorSimulator工具后,下载完成后得到一个sensorsimulator-2.0-rc1.zip压缩包。解压该文件,得到如下文件结构。
安装SensorSimulator的手机端程序。通过命令窗口进入到上面文件的bin目录下,输入如下命令来安装SensorSimulatorSettings-2.0-rc1.apk文件。adb install SensorSimulatorSettings-2.0-rc1.apk
运行SensorSimulator的PC端程序,通过命令窗口进入到上面文件的bin目录下,并在窗口内执行如下命令:java –jar sensorsimulator-2.0-rc1.jar。运行该程序出现如下界面。
运行SensorSimulator的手机端程序。
在SensorSimulator的手机端程序中填写SensorSimulator的PC端程序的监听IP地址、监听端口。
切换到SensorSimulator的Testting Tab页,单击该Tab里的Connect按钮,SensorSimulator手机端和PC端连接。
1.3 利用SensorSimulator开发传感器应用
通过使用SensorSimulator,接下来就可以在Android模拟器中开发、调试传感器应用了。不过使用SensorSimulator开发传感器应用与开发真实的传感器应用略有区别。
Android应用必须通过引用外部JAR包的形式来引用SensorSimulator的lib目录下的sensorsimulator-2.0-rc1.jar包。
在应用项目上右键单击选择“Build Path” à “Add External Archives…”,找到sensorsimulator-2.0-rc1.jar所在位置,将其添加到项目中。
应用程序编程使用SensorManagerSimulator代替了原有的SensorManager。
应用程序获取SensorManagerSimulator之后,需要调用connectSimulator()方法连接模拟器。
应用程序编程时所用的Sensor、SensorEvent、 SensorEventListener等不再是Android提供的类,而是由SensorSimulator提供的类。
应用程序需要访问网络的权限。
例:利用传感模拟工具开发加速度传感器:
import org.openintents.sensorsimulator.hardware.SensorManagerSimulator;
import org.openintents.sensorsimulator.hardware.Sensor;
import org.openintents.sensorsimulator.hardware.SensorEvent;
import org.openintents.sensorsimulator.hardware.SensorEventListener;
import android.app.Activity;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.widget.EditText;
public class AccelSimulatorTest extends Activity
implements SensorEventListener
{
// 定义模拟器的Sensor管理器
private SensorManagerSimulator mSensorManager;
// 定义界面上的文本框组件
EditText etTxt1;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取程序界面的文本框组件
etTxt1 = (EditText) findViewById(R.id.txt1);
// 获取传感器模拟器的传感器管理服务
mSensorManager = SensorManagerSimulator.getSystemService(
this, SENSOR_SERVICE);
// 连接传感器模拟器
mSensorManager.connectSimulator();
}
@Override
protected void onResume()
{
super.onResume();
// 为系统的加速度传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
// 取消注册
mSensorManager.unregisterListener(this);
super.onStop();
}
// 以下是实现SensorEventListener接口必须实现的方法
// 当传感器的值发生改变时回调该方法
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
StringBuilder sb = new StringBuilder();
sb.append(X方向上的加速度:);
sb.append(values[0]);
sb.append(
Y方向上的加速度:);
sb.append(values[1]);
sb.append(
Z方向上的加速度:);
sb.append(values[2]);
etTxt1.setText(sb.toString());
}
@Override
// 当传感器精度改变时回调该方法。
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
<!-- 通过模拟器调试需要访问网络 -->
<uses-permission android:name="android.permission.INTERNET/"></uses-permission>
Android的常用传感器
2.1加速度传感器Accelerometer
加速度传感器主要感应手机的运动,在注册了传感器监听器后加速度传感器主要捕获3个参数values[0]、values[1]、values[2]。
values[0]:空间坐标系中x轴方向上的加速度减去重力加速度减去中立加速度在x轴上的分量。
values[1]:空间坐标系中x轴方向上的加速度减去重力加速度减去中立加速度在y轴上的分量。
values[2]:空间坐标系中x轴方向上的加速度减去重力加速度减去中立加速度在z轴上的分量。
上述3个数据的单位均为米每二次方秒。
距离说明:
当手机平放到桌面静止时,加速度为重力加速度g,通过0减去-g(重力加速度g方向为z轴反方向,故为负值)得到values[2]为g。
如果把手机水平方向右推,此时手机x方向上的加速度为正,即values[0]为正。
当把手机以a米每二次方秒的加速度竖值向上举时,values[2]的返回值为(a+g)米每二次方秒,通过a减去-g得到。
2.2 方向传感器Orientation
方向传感器主要感应手机方位的变化,其每次读取的都是静态的状态值,在注册了传感器监听器后方向传感器主要捕获3个参数values[0]、values[1]、values[2],关于三个角度的说明如下:
第一个角度:表示手机顶部朝向与正北方向的夹角。当手机绕着Z轴旋转时,该角度值发生改变。
第二个角度:表示手机顶部或尾部翘起的角度,当手机绕着X轴倾斜时,该角度值发生变化。
第三个角度:表示手机左侧或右侧翘起的角度。当手机绕着Y轴倾斜时,该角度值发生变化。
2.3磁场传感器Magnetic Field
磁场传感器主要用于感应周围的磁感应强度。即使周围没有任何直接的磁场,手机设备也始终会处于地球磁场中。随着手机状态设备摆放状态的改变,周围磁场在手机的X、Y、Z方向上的会发生改变。
磁场传感器传感器会返回三个数据,三个数据分别代表周围磁场分解到X、Y、Z三个方向上的磁场分量。磁场数据的单位是微特斯拉(uT)。
2.4光传感器Light
光传感器用于感应周围的光强,注册监听器后只捕获一个参数:values[0]。该参数代表周围的光照强度,单位为勒克斯(lux)。
2.5温度传感器Temperature
温度传感器用于获取手机设备所处环境的温度。温度传感器会返回一个数据,该数据代表手机设备周围的温度,单位是摄氏度。
2.6压力传感器 Pressure
压力传感器用于获取手机设备所处环境的压力的大小。压力传感器会返回一个数据,代表手机设备周围的压力大小。
例:传感器应用:
SensorSimulatorTest.java
public class SensorSimulatorTest extends Activity
implements SensorEventListener
{
// // 定义真机的Sensor管理器
// private SensorManager mSensorManager;
// 定义模拟器的Sensor管理器
private SensorManagerSimulator mSensorManager;
EditText etOrientation;
EditText etMagnetic;
EditText etTemerature;
EditText etLight;
EditText etPressure;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取界面上的EditText组件
etOrientation = (EditText) findViewById(R.id.etOrientation);
etMagnetic = (EditText) findViewById(R.id.etMagnetic);
etTemerature = (EditText) findViewById(R.id.etTemerature);
etLight = (EditText) findViewById(R.id.etLight);
etPressure = (EditText) findViewById(R.id.etPressure);
// 获取真机的传感器管理服务
// mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// 获取传感器模拟器的传感器管理服务
mSensorManager = SensorManagerSimulator.getSystemService(this,
SENSOR_SERVICE);
// 连接传感器模拟器
mSensorManager.connectSimulator();
}
@Override
protected void onResume()
{
super.onResume();
// 为系统的方向传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的磁场传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的温度传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_TEMPERATURE),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的光传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT),
SensorManager.SENSOR_DELAY_GAME);
// 为系统的压力传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onStop()
{
// 程序退出时取消注册传感器监听器
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
protected void onPause()
{
// 程序暂停时取消注册传感器监听器
mSensorManager.unregisterListener(this);
super.onPause();
}
// 以下是实现SensorEventListener接口必须实现的方法
@Override
// 当传感器精度改变时回调该方法。
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
// // 真机上获取触发event的传感器类型
// int sensorType = event.sensor.getType();
// 模拟器上获取触发event的传感器类型
int sensorType = event.type;
StringBuilder sb = null;
// 判断是哪个传感器发生改变
switch (sensorType)
{
// 方向传感器
case Sensor.TYPE_ORIENTATION:
sb = new StringBuilder();
sb.append(绕Z轴转过的角度:);
sb.append(values[0]);
sb.append(
绕X轴转过的角度:);
sb.append(values[1]);
sb.append(
绕Y轴转过的角度:);
sb.append(values[2]);
etOrientation.setText(sb.toString());
break;
// 磁场传感器
case Sensor.TYPE_MAGNETIC_FIELD:
sb = new StringBuilder();
sb.append(X方向上的角度:);
sb.append(values[0]);
sb.append(
Y方向上的角度:);
sb.append(values[1]);
sb.append(
Z方向上的角度:);
sb.append(values[2]);
etMagnetic.setText(sb.toString());
break;
// 温度传感器
case Sensor.TYPE_TEMPERATURE:
sb = new StringBuilder();
sb.append(当前温度为:);
sb.append(values[0]);
etTemerature.setText(sb.toString());
break;
// 光传感器
case Sensor.TYPE_LIGHT:
sb = new StringBuilder();
sb.append(当前光的强度为:);
sb.append(values[0]);
etLight.setText(sb.toString());
break;
// 压力传感器
case Sensor.TYPE_PRESSURE:
sb = new StringBuilder();
sb.append(当前压力为:);
sb.append(values[0]);
etPressure.setText(sb.toString());
break;
}
}
}
传感器应用案例
对传感器的支持是Android系统的特性之一,通过使用传感器可以开发出各种有趣的应用,我们通过方向传感器来开发指南针。
开发指南针的思路比较简单:程序先准备一张指南针图片,该图片上方向指针指向北方。接下来开发一个检测方向的传感器,程序检测到手机顶部绕Z轴转过多少度,让指南针图片反向转过多少度即可。
该应用中只要在界面中添加一张图片,并让图片总是反向转过方向传感器反回的第一个角度即可。
例:指南针:
Compass.java
public class Compass extends Activity
implements SensorEventListener
{
// 定义显示指南针的图片
ImageView znzImage;
// 记录指南针图片转过的角度
float currentDegree = 0f;
// 定义模拟器的Sensor管理器
// private SensorManagerSimulator mSensorManager;
// 定义真机的Sensor管理器
SensorManager mSensorManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取界面中显示指南针的图片
znzImage = (ImageView) findViewById(R.id.znzImage);
// 获取真机的传感器管理服务
mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// // 获取传感器模拟器的传感器管理服务
// mSensorManager = SensorManagerSimulator.getSystemService(this,
// SENSOR_SERVICE);
// // 连接传感器模拟器
// mSensorManager.connectSimulator();
}
@Override
protected void onResume()
{
super.onResume();
// 为系统的方向传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause()
{
// 取消注册
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onStop()
{
// 取消注册
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onSensorChanged(SensorEvent event)
{
// 真机上获取触发event的传感器类型
int sensorType = event.sensor.getType();
// // 模拟器上获取触发event的传感器类型
// int sensorType = event.type;
switch (sensorType)
{
case Sensor.TYPE_ORIENTATION:
// 获取绕Z轴转过的角度。
float degree = event.values[0];
// 创建旋转动画(反向转过degree度)
RotateAnimation ra = new RotateAnimation(currentDegree,
-degree, Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
// 设置动画的持续时间
ra.setDuration(200);
// 运行动画
znzImage.startAnimation(ra);
currentDegree = -degree;
break;
}
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
}
<!--?xml version=1.0 encoding=utf-8?-->
<linearlayout android:background="#fff"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<imageview android:id="@+id/znzImage"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:scaletype="fitCenter"
android:src="@drawable/znz">
</imageview>
</linearlayout>
例:水平仪:
Gradienter.java
public class Gradienter extends Activity implements SensorEventListener
{
// 定义水平仪的仪表盘
MyView show;
// 定义水平仪能处理的最大倾斜角,超过该角度,气泡将直接在位于边界。
int MAX_ANGLE = 30;
// // 定义真机的Sensor管理器
// SensorManager mSensorManager;
// 定义模拟器的Sensor管理器
SensorManagerSimulator mSensorManager;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 获取水平仪的主组件
show = (MyView) findViewById(R.id.show);
// 获取真机的传感器管理服务
// mSensorManager = (SensorManager)getSystemService(SENSOR_SERVICE);
// 获取传感器模拟器的传感器管理服务
mSensorManager = SensorManagerSimulator.getSystemService(this,
SENSOR_SERVICE);
// 连接传感器模拟器
mSensorManager.connectSimulator();
}
@Override
public void onResume()
{
super.onResume();
// 为系统的方向传感器注册监听器
mSensorManager.registerListener(this,
mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION),
SensorManager.SENSOR_DELAY_GAME);
}
@Override
protected void onPause()
{
// 取消注册
mSensorManager.unregisterListener(this);
super.onPause();
}
@Override
protected void onStop()
{
// 取消注册
mSensorManager.unregisterListener(this);
super.onStop();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy)
{
}
@Override
public void onSensorChanged(SensorEvent event)
{
float[] values = event.values;
// // 真机上获取触发event的传感器类型
// int sensorType = event.sensor.getType();
// 模拟器上获取触发event的传感器类型
int sensorType = event.type;
switch (sensorType)
{
case Sensor.TYPE_ORIENTATION:
// 获取与Y轴的夹角
float yAngle = values[1];
// 获取与Z轴的夹角
float zAngle = values[2];
// 气泡位于中间时(水平仪完全水平),气泡的X、Y座标
int x = (show.back.getWidth() - show.bubble.getWidth()) / 2;
int y = (show.back.getHeight() - show.bubble.getHeight()) / 2;
// 如果与Z轴的倾斜角还在最大角度之内
if (Math.abs(zAngle) <= MAX_ANGLE)
{
// 根据与Z轴的倾斜角度计算X座标的变化值(倾斜角度越大,X座标变化越大)
int deltaX = (int) ((show.back.getWidth() - show.bubble
.getWidth()) / 2 * zAngle / MAX_ANGLE);
x += deltaX;
}
// 如果与Z轴的倾斜角已经大于MAX_ANGLE,气泡应到最左边
else if (zAngle > MAX_ANGLE)
{
x = 0;
}
// 如果与Z轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边
else
{
x = show.back.getWidth() - show.bubble.getWidth();
}
// 如果与Y轴的倾斜角还在最大角度之内
if (Math.abs(yAngle) <= MAX_ANGLE)
{
// 根据与Y轴的倾斜角度计算Y座标的变化值(倾斜角度越大,Y座标变化越大)
int deltaY = (int) ((show.back.getHeight() - show.bubble
.getHeight()) / 2 * yAngle / MAX_ANGLE);
y += deltaY;
}
// 如果与Y轴的倾斜角已经大于MAX_ANGLE,气泡应到最下边
else if (yAngle > MAX_ANGLE)
{
y = show.back.getHeight() - show.bubble.getHeight();
}
// 如果与Y轴的倾斜角已经小于负的MAX_ANGLE,气泡应到最右边
else
{
y = 0;
}
// 如果计算出来的X、Y座标还位于水平仪的仪表盘内,更新水平仪的气泡座标
if (isContain(x, y))
{
show.bubbleX = x;
show.bubbleY = y;
}
// 通知系统重回MyView组件
show.postInvalidate();
break;
}
}
// 计算x、y点的气泡是否处于水平仪的仪表盘内
private boolean isContain(int x, int y)
{
// 计算气泡的圆心座标X、Y
int bubbleCx = x + show.bubble.getWidth() / 2;
int bubbleCy = y + show.bubble.getWidth() / 2;
// 计算水平仪仪表盘的圆心座标X、Y
int backCx = show.back.getWidth() / 2;
int backCy = show.back.getWidth() / 2;
// 计算气泡的圆心与水平仪仪表盘的圆心之间的距离。
double distance = Math.sqrt((bubbleCx - backCx) * (bubbleCx - backCx)
+ (bubbleCy - backCy) * (bubbleCy - backCy));
// 若两个圆心的距离小于它们的半径差,即可认为处于该点的气泡依然位于仪表盘内
if (distance < (show.back.getWidth() - show.bubble.getWidth()) / 2)
{
return true;
}
else
{
return false;
}
}
}
MyView.java
public class MyView extends View
{
// 定义水平仪仪表盘图片
Bitmap back;
// 定义水平仪中的气泡图标
Bitmap bubble;
// 定义水平仪中气泡 的X、Y座标
int bubbleX, bubbleY;
public MyView(Context context, AttributeSet attrs)
{
super(context, attrs);
// 加载水平仪图片和气泡图片
back = BitmapFactory.decodeResource(getResources()
, R.drawable.back);
bubble = BitmapFactory
.decodeResource(getResources(), R.drawable.bubble);
}
@Override
protected void onDraw(Canvas canvas)
{
super.onDraw(canvas);
// 绘制水平仪表盘图片
canvas.drawBitmap(back, 0, 0, null);
// 根据气泡座标绘制气泡
canvas.drawBitmap(bubble, bubbleX, bubbleY, null);
}
}
<!--?xml version=1.0 encoding=utf-8?-->
<framelayout android:background="#fff"
android:layout_height="fill_parent"
android:layout_width="fill_parent"
android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.boby.sensor.myview
android:id="@+id/show"
android:layout_height="fill_parent"
android:layout_width="fill_parent">
</com.boby.sensor.myview></framelayout>