1 传感器简介
传感器 Sensor 是一种检测装置,能感受到被测量的信息,并能将感受到的信息,按一定规律变换成为电信号或其他所需形式的信息输出,以满足信息的传输、处理、存储、显示、记录和控制等要求。 Android 提供了对设备传感器的支持,只要 Android 设备的硬件提供了这些传感器,Android 应用可以通过传感器来获取设备的外界条件,包括手机的运行状态、当前摆放的方向等。Android 系统还提供了驱动程序去管理这些传感器硬件,可以通过监听器的方式监听传感器硬件感知到的外部环境的变化。Android 平台支持三大类传感器:
类别 | 传感器 | 说明 | 运动传感器 | TYPE_ACCELEROMETER | 加速度传感器,基于硬件 | TYPE_GRAVITY | 重力传感器,基于硬件或软件 | TYPE_GYROSCOPE | 陀螺仪传感器,基于硬件 | TYPE_ROTATION_VECTOR | 旋转矢量传感器,基于硬件或软件 | TYPE_LINEAR_ACCELERATION | 线性加速度传感器,基于硬件或软件 | 位置传感器 | TYPE_MAGNETIC_FIELD | 磁力传感器,基于硬件 | TYPE_ORIENTATION | 方向传感器,基于软件 | TYPE_PROXIMITY | 距离传感器,基于硬件 | 环境传感器 | TYPE_LIGHT | 光线感应传感器,基于硬件 | TYPE_PRESSURE | 压力传感器,基于硬件 | TYPE_TEMPERATURE | 温度传感器,基于硬件 | 有些传感器基于硬件,有些基于软件。基于硬件的传感器是内置在手机或平板设备中的物理组件。这类传感器通过直接测量特定的环境属性(如加速度、地磁场强度或角度变化)来采集数据。基于软件的传感器不是物理设备,它们只是模仿基于硬件的传感器。基于软件的传感器从一个或多个基于硬件的传感器获取数据,有时被称为虚拟传感器或合成传感器。比如线性加速度传感器和重力传感器就是基于软件的传感器。
传感器弃用说明:
- Android 2.2(API 级别 8)已弃用方向传感器,Android 4.4W(API 级别 20)已弃用此传感器类型
TYPE_ORIENTATION。替代方法见后面示例代码。 - 温度传感器已在 Android 4.0(API 级别 14)中弃用,不同设备具有不同的实现。
2 传感器的使用
2.1 获取传感器服务
Android 中内置了很多系统级的服务,用于给开发人员使用,而传感器也是通过传感器服务 SensorManager 来管理的。而在 Android 组件中获取系统服务,使用方法 Context.getSystemService(String) 即可,它的参数均以 static final 的方式定义在 Context 中,而获取 SensorManager 需要传入 Context.SENSOR_SERVICE。
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
2.2 获取待监听的传感器
传感器服务管理设备上所有的传感器,所以需要获取待监听的传感器。 可以通过在 getSensorList() 方法中传入 TYPE_ALL 来获取设备上的所有传感器:
List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
也可以通过指定的 type 参数获取到相对应的传感器,如果设备上有多个特定类型的传感器,则必须将其中一个指定为默认传感器。如果没有指定默认传感器,则该方法调用会返回 null,这表示设备没有该类型的传感器。
Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
注意使用前先判断传感器是否存在。
if (sensor != null) {
} else {
}
- 使用清单文件来限定目标设备必须带有指定传感器配置。
<uses-feature
android:name="android.hardware.sensor.accelerometer"
android:required="true" />
对于某一个传感器,它的一些具体信息的获取方法如下:
- getMaximumRange() 最大取值范围
- getName() 设备名称
- getPower() 功率
- getResolution() 精度
- getType() 传感器类型
- getVentor() 设备供应商
- getVersion() 设备版本号
2.3 注册传感器的监听器
获得 SensorManager 和 Sensor 对象之后,就可以为其 Sensor 注册监听器了。为传感器注册监听器,使用 SensorManager.registerListener() 方法即可,它存在多个重载方法,但是有些方法已经过时了,下面提供一个常用的方法:
boolean registerListener(SensorEventListener listener,Sensor sensor,int rateUs)
上面方法参数的意义:listener:传感器的监听器、sensor:待监听的传感器、rateUs:传感器的采样率。 从 registerListener() 方法可以看出,它需要传递一个 SensorEventListener 对象,它就是传感器的监听器,其中包含两个方法,需要开发人员去实现它:
- void onSensorChanged(SensorEvent event):当传感器感应的值发生变化时回调。
- void onAccuracyChanged(Sensor sensor,int accuracy):当传感器精度发生变化时回调。
对于上面两个方法,传感器的精度一般是不会发生改变的,所以我们一般主要的代码量在 onSensorChanged()中。
在 onSensorChanged(SensorEvent event) 方法中有一个参数 event,通过 event 可以获取传感器的类型以及传感器的数据。
- 获取传感器的类型:event.sensor.getType()
- 获取传感器的数据:event.values[i],i为0,1,2…,不同传感器,event.values[i] 对应的数据不同。以加速度传感器为例,values[0] 表示x轴上的加速度,values[1] 表示y轴上的加速度,values[2] 表示z轴上的加速度。
registerListener() 方法还有一个 rateUs 的参数,它表示监听传感器改变的采样率,就是从传感器获取值的频率。它被定义以 static final 的形式定义在 SensorManager 中,方便我们直接使用,它定义了如下几个参数:
参数 | 延时 | 说明 |
---|
SensorManager.SENSOR_DELAY_FASTEST | 0ms | 一般不是特别敏感的处理不推荐使用,该种模式可能造成手机电力大量消耗,由于传递的为原始数据,算法不处理好将会影响游戏逻辑和 UI 的性能。 | SensorManager.SENSOR_DELAY_GAME | 20ms | 一般绝大多数的实时性较高的游戏都使用该级别。 | SensorManager.SENSOR_DELAY_UI | 60ms | 适合普通用户界面 UI 变化的频率,相对节省电能和逻辑处理,一般游戏开发中不使用。 | SensorManager.SENSOR_DELAY_NORMAL | 200ms | 对于一般的益智类或 EASY 级别的游戏可以使用,但过低的采样率可能对一些赛车类游戏有跳帧现象。 |
Android 为我们提供了这几个采样率的参数,方便我们使用。但对于选择那种采样率而言,并不是越快越好,要参照实际开发的应用的情况来说,采样率越大,将越耗费资源,包括电量、CPU 等,所以要根据实际情况选择,毕竟再强大的应用,如果造成设备续航能力的降低,也是会被用户所不喜的。
2.4 注销传感器的监听器
当使用完传感器之后,需要为其注销监听器,因为传感器的监听器并不会因为应用的结束而自行释放资源,需要开发人员在适当的时候主动注销。注销传感器监听器使用 SensorManager.unregisterListener() 方法即可,和监听器的注册方法一样,它也具有多个重载的方法,但是有一些已经被弃用了,下面介绍一个常用的:
void unregisterListener(SensorEventListener listener)
3 示例代码
Java 代码如下:
public class MainActivity extends AppCompatActivity {
private final String TAG = "sensor-sample";
private TextView mAccelerometerSensorTextView;
private TextView mMagneticSensorTextView;
private TextView mGyroscopeSensorTextView;
private TextView mOrientationSensorTextView;
private SensorManager mSensorManager;
private MySensorEventListener mMySensorEventListener;
private float[] mAccelerometerReading = new float[3];
private float[] mMagneticFieldReading = new float[3];
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAccelerometerSensorTextView = findViewById(R.id.accelerometer_sensor);
mMagneticSensorTextView = findViewById(R.id.magnetic_sensor);
mGyroscopeSensorTextView = findViewById(R.id.gyroscope_sensor);
mOrientationSensorTextView = findViewById(R.id.orientation_sensor);
this.mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
this.mMySensorEventListener = new MySensorEventListener();
}
@Override
protected void onResume() {
super.onResume();
if (mSensorManager == null) {
return;
}
Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (accelerometerSensor != null) {
mSensorManager.registerListener(mMySensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.d(TAG, "Accelerometer sensors are not supported on current devices.");
}
Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
if (magneticSensor != null) {
mSensorManager.registerListener(mMySensorEventListener, magneticSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.d(TAG, "Magnetic sensors are not supported on current devices.");
}
Sensor gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
if (gyroscopeSensor != null) {
mSensorManager.registerListener(mMySensorEventListener, gyroscopeSensor, SensorManager.SENSOR_DELAY_UI);
} else {
Log.d(TAG, "Gyroscope sensors are not supported on current devices.");
}
}
@Override
protected void onPause() {
super.onPause();
if (mSensorManager == null) {
return;
}
mSensorManager.unregisterListener(mMySensorEventListener);
}
private void calculateOrientation() {
final float[] rotationMatrix = new float[9];
SensorManager.getRotationMatrix(rotationMatrix, null, mAccelerometerReading, mMagneticFieldReading);
final float[] orientationAngles = new float[3];
SensorManager.getOrientation(rotationMatrix, orientationAngles);
Log.d(TAG, "orientation data[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
mOrientationSensorTextView.setText("[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
}
private class MySensorEventListener implements SensorEventListener {
@Override
public void onSensorChanged(SensorEvent event) {
if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
mAccelerometerReading = event.values;
Log.d(TAG, "accelerometer data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mAccelerometerSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
} else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
mMagneticFieldReading = event.values;
Log.d(TAG, "magnetic data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mMagneticSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
} else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
Log.d(TAG, "gyroscope data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
mGyroscopeSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
}
calculateOrientation();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.d(TAG, "onAccuracyChanged:" + sensor.getType() + "->" + accuracy);
}
}
}
运行效果如下:
示例代码下载:sensor-sample
详细参考 Android 开发者官方文档:传感器
|