每个人都应该熟悉手机上的传感器,如方向传感器、陀螺仪、重力传感器、光传感器等。现在手机基本集成至少有十几种传感器,面向未来的人工智能,这种知识也是我们必须的。
传感器分类
Android 平台支持三类传感器:
- 动态传感器 这种传感器测量三个轴向上的加速力和旋转力。
加速传感器
、重力传感器
、陀螺仪
和旋转矢量传感器
。 - 环境传感器 这种传感器测量各种环境参数,如环境温度、压力、照明和湿度。该类别包括
气压计
、光度计
和温度计
。 - 位置传感器 这种传感器测量设备的物理位置。这一类包括
屏幕方向传感器
和磁力计(电子罗盘)
。
传感器使用
Android平台上google它为我们提供了一个非常方便的传感器框架,我们只需要定义我们想要使用的传感器并实现它的逻辑。
传感器框架是 android.hardware
以下类别和接口主要用于软件包的一部分开发和使用:
- SensorManager
- Sensor
- SensorEventListener
- SensorEvent
SensorManager mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
// 获取传感器的类型(TYPE_ACCELEROMETER:加速度传感器) Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
这里指定的传感器类型有很多种,这里暂且列举一些最常用的传感器:
- Sensor.TYPE_ACCELEROMETER: 三轴加速度传感器
- Sensor.TYPE_ORIENTATION:方向传感器
- Sensor.TYPE_GYROSCOPE:陀螺仪传感器
- Sensor.TYPE_MAGNETIC_FIELD:磁力传感器
- Sensor.TYPE_GRAVITY:重力传感器
- Sensor.TYPE_LINEAR_ACCELERATION:线性加速度传感器
- Sensor.TYPE_AMBIENT_TEMPERATURE:温度传感器
- Sensor.TYPE_LIGHT:光传感器
- Sensor.TYPE_PRESSURE:压力传感器
- Sensor.TYPE_ALL:所有类型的传感器都通过
getSensorList
返回所有支持的传感器列表。
SensorEventListener mListener = new SensorEventListener() {
// 当传感器值发生变化时,回调该方法 @Override public void onSensorChanged(SensorEvent event) {
// Do something with this sensor value. // The light sensor returns a single value. // Many sensors return 3 values, one for each axis. } // 当传感器精度发生变化时,回调该方法 @Override public void onAccuracyChanged(Sensor sensor, int accuracy) {
// Do something here if sensor accuracy changes. } } mSensorManager.registerListener(mListener, mSensor, SensorManager.SENSOR_DELAY_GAME);
其中registerListener最后一个参数是指定传感器获取数据的频率,有四种形式:
- SensorManager.SENSOR_DELAY_NORMAL,正常频率适用于实时性要求低的应用频率。
- SensorManager.SENSOR_DELAY_FASTEST,最快,延迟最小,同时也最消耗资源,一般只有特别依赖传感器的应用使用该频率,否则不推荐。
- SensorManager.SENSOR_DELAY_GAME,适合游戏的频率,一般有实时性要求的应用适合使用这种频率。
- SensorManager.SENSOR_DELAY_UI,适合普通应用的频率,这种模式比较省电,而且系统开销小,但延迟大,因此只适合普通小程序使用。
一旦传感器监测到环境数据变化,便会回调两个实现方法:
-
onSensorChanged(SensorEvent event):传感器报告了新值。 内部的SensorEvent 对象包含关于新传感器数据的信息,包括:数据的准确度、生成数据的传感器、生成数据的时间戳以及传感器记录的新数据,系统可能会频繁调用,切记。
-
onAccuracyChanged(Sensor sensor, int accuracy):传感器的准确度发生了变化。 当传感器精度发生变化时onAccuracyChanged被触发。第一参数是发生变化的sensor对象,第二个参数是传感器的新精度(准确度)。精度有以下四种:
- SENSOR_STATUS_ACCURACY_LOW:低精度值
- SENSOR_STATUS_ACCURACY_MEDIUM:平均精度值
- SENSOR_STATUS_ACCURACY_HIGH:高精度值
- SENSOR_STATUS_UNRELIABLE:精度值不可靠
mSensorManager.unregisterListener(mListener)
传感器几乎是非常消耗资源的,最佳的做法是始终停用不需要的传感器,特别是在活动处于暂停状态时。如果不这样做,可能会在几小时内将电池电量耗尽。
第三步和第四步开发过程中一般是相呼应的,我们常常在onResume中进行注册,在onPause中进行解注册,也可根据业务需要自行确定时机。
运行时检测传感器
有时我们不能确定当前设备是否包含我们所需的传感器,所以在运行时我们需要做一个判断:
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE);
if(sensor != null){
// Success! There's a pressure sensor.
}else{
// Failure! No pressure sensor.
}
如果您要在 Google Play 上发布应用,您可以在清单文件中使用 <uses-feature>
元素,以对不具备适合您应用的传感器配置的设备屏蔽您的应用,以下清单示例条目会对没有加速度计的设备屏蔽应用:
<uses-feature android:name="android.hardware.sensor.accelerometer"
android:required="true" />
传感器坐标系
大部分传感器都是以三轴坐标来表示数据值。对于大多数传感器,当设备处于(平板和手机就有可能不一样)时,会相对于设备屏幕来定义坐标系,如下图:
以下传感器使用此坐标系:
- 加速度传感器
- 重力传感器
- 陀螺仪
- 线性加速度传感器
- 地磁场传感器
记着,传感器的坐标系是始终跟随设备的。
小栗子
下边就是通过三轴加速度传感器实现一个计步器功能,代码来源于网络,个人稍加注释:
public class StepDetector implements SensorEventListener{
private final static String TAG = "StepDetector";
private float mLimit = 10;
private float mLastValues[] = new float[3*2];
private float mScale[] = new float[2];
private float mYOffset;
private float mLastDirections[] = new float[3*2];
private float mLastExtremes[][] = {
new float[3*2], new float[3*2] };
private float mLastDiff[] = new float[3*2];
private int mLastMatch = -1;
private ArrayList<StepListener> mStepListeners = new ArrayList<StepListener>();
public StepDetector() {
// 手机屏幕的高
int h = 480;
// 中心点,y轴的偏移量
mYOffset = h * 0.5f;
// 获取重力相关参数
mScale[0] = - (h * 0.5f * (1.0f / (SensorManager.STANDARD_GRAVITY * 2)));
mScale[1] = - (h * 0.5f * (1.0f / (SensorManager.MAGNETIC_FIELD_EARTH_MAX)));
}
public void setSensitivity(float sensitivity) {
//灵敏度 1.97 2.96 4.44 6.66 10.00 15.00 22.50 33.75 50.62
mLimit = sensitivity;
}
public void addStepListener(StepListener sl) {
mStepListeners.add(sl);
}
//public void onSensorChanged(int sensor, float[] values) {
public void onSensorChanged(SensorEvent event) {
Sensor sensor = event.sensor;
synchronized (this) {
int j = (sensor.getType() == Sensor.TYPE_ACCELEROMETER) ? 1 : 0;
if (j == 1) {
//三个方向上的速度和
float vSum = 0;
for (int i=0 ; i<3 ; i++) {
final float v = mYOffset + event.values[i] * mScale[j];
vSum += v;
}
int k = 0;
//平均速度
float v = vSum / 3;
float direction = (v > mLastValues[k] ? 1 : (v < mLastValues[k] ? -1 : 0));
if (direction == - mLastDirections[k]) {
// Direction changed
int extType = (direction > 0 ? 0 : 1); // minumum or maximum?
mLastExtremes[extType][k] = mLastValues[k];
float diff = Math.abs(mLastExtremes[extType][k] - mLastExtremes[1 - extType][k]);
//运动太慢,忽略
if (diff > mLimit) {
boolean isAlmostAsLargeAsPrevious = diff > (mLastDiff[k]*2/3);
boolean isPreviousLargeEnough = mLastDiff[k] > (diff/3);
boolean isNotContra = (mLastMatch != 1 - extType);
//判断有效的一步
if (isAlmostAsLargeAsPrevious && isPreviousLargeEnough && isNotContra) {
Log.i(TAG, "step");
for (StepListener stepListener : mStepListeners) {
stepListener.onStep();
}
mLastMatch = extType;
}
else {
mLastMatch = -1;
}
}
mLastDiff[k] = diff;
}
mLastDirections[k] = direction;
mLastValues[k] = v;
}
}
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}
参考
- https://developer.android.com/guide/topics/sensors/sensors_overview