文章目录
- 概述
- getOrientation 方法根据 旋转矩阵R 获取 设备旋转弧度
- getRotationMatrix 方法根据 地磁场、加速度传感器对象 获取 旋转矩阵R
- 代码
- 参考资料
概述
Sensor.TYPE_ORIENTATION 常数在 API 8 中已弃用,官方推荐使用 SensorManager.getOrientation()
替代。关于 Orientation Sensor(被弃用的方向传感器) 在官方文档中的概述里有这样一句话:
The orientation sensor is software-based and derives its data from the accelerometer and the geomagnetic field sensor. (方向传感器是基于软件的,并且它的数据是通过加速度传感器和磁场传感器共同获得的)
上面的描述其实少了一个重要角色,即 SensorManager.getOrientation()
。方向传感器 在被弃用之前,正是通过 SensorManager.getOrientation()
来借助 加速度传感器(Sensor.TYPE_ACCELEROMETER) 和 地磁场传感器(TYPE_MAGNETIC_FIELD) 的数据得到的。
getOrientation 方法根据 旋转矩阵R 获取 设备旋转弧度
官方文档中,对于 getOrientation
方法的介绍如下:
该函数有两个参数,R
和 values
。传入时 R
有具体值而 values
是空的,然后在方法内部根据 旋转矩阵R 计算设备的方向,将结果存储在 values
中:
- values[0] 记录着手机围绕 Z 轴的旋转弧度
- values[1] 记录着手机围绕 X 轴的旋转弧度
- values[2] 记录着手机围绕 Y 轴的旋转弧度
而后可以通过 Math.toDegrees()
方法将旋转弧度转化为角度。
但是这里还有个问题,旋转矩阵R 的值从何而来呢?事实上,其值通过我们之前提到 加速度传感器(Sensor.TYPE_ACCELEROMETER) 和 地磁场传感器(TYPE_MAGNETIC_FIELD) 的获得。
首先通过 SensorEvent
对象获得两个传感器对象 Sensor
,一个是 加速度传感器,另一个是 地磁场传感器。
public void onSensorChanged(SensorEvent event) {// SensorEvent:保存精度(accuracy)、传感器类型(sensor)、时间戳(timestamp)// 以及不同传感器(Sensor)具有的不同传感器数组(values)。SensorManager.getOrientation(r, values);// TYPE_MAGNETIC_FIELD:描述磁场传感器类型的常量。if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {geomagnetic = event.values; // 地磁场传感器对象}// TYPE_ACCELEROMETER:描述加速度传感器类型的常量。if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {gravity = event.values; // 加速度传感器对象}
}
getRotationMatrix 方法根据 地磁场、加速度传感器对象 获取 旋转矩阵R
之后通过这两个对象结合 SensorManager.getRotationMatrix()
方法获取 旋转矩阵R 的具体值。官方文档中,对于 getRotationMatrix
方法的介绍如下:
该函数有四个参数,通过计算 gravity
和 geomagnetic
得到 旋转矩阵R。(第二个参数 倾斜矩阵I 用于将磁场数据转换进实际的重力坐标系中,一般默认设置为NULL即可。)
代码
/** 方向传感器 */
public class MyOrientationListener implements SensorEventListener {private static final String TAG = "WeatherActivity";private final Context context;private SensorManager sensorManager;private Sensor magneticSensor, accelerometerSensor;private float[] gravity = new float[3];private float[] geomagnetic= new float[3];private OnOrientationListener onOrientationListener; //内部接口实现回调private double lastX;/** 当有新的传感器事件时(手机方向改变时调用)调用。 */@Overridepublic void onSensorChanged(SensorEvent event) {Log.e(TAG, "onSensorChanged 开始");// SensorEvent:保存精度(accuracy)、传感器类型(sensor)、时间戳(timestamp)// 以及不同传感器(Sensor)具有的不同传感器数组(values)。// TYPE_MAGNETIC_FIELD:描述磁场传感器类型的常量。if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {geomagnetic = event.values;Log.e(TAG, "onSensorChanged 得到磁场传感器: " + Arrays.toString(geomagnetic));}// TYPE_ACCELEROMETER:描述加速度传感器类型的常量。if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {gravity = event.values;Log.e(TAG, "onSensorChanged 得到加速度传感器: " + Arrays.toString(gravity));}getValue();}/** 当注册传感器的精度发生变化时调用。 */@Overridepublic void onAccuracyChanged(Sensor sensor, int accuracy) {}/** 通过加速度和磁场变化获取方向变化的信息 */public void getValue() {//初始化数组float[] values = new float[3]; // 用来保存手机的旋转弧度float[] r = new float[9]; // 被填充的旋转矩阵// 传入gravity和geomagnetic,通过计算它们得到旋转矩阵R。// 而第二个参数倾斜矩阵I是用于将磁场数据转换进实际的重力坐标系中的,一般默认设置为NULL即可。SensorManager.getRotationMatrix(r, null, gravity, geomagnetic);// 根据旋转矩阵R计算设备的方向,将结果存储在values中。// values[0]记录着手机围绕 Z 轴的旋转弧度,// values[1]记录着手机围绕 X 轴的旋转弧度,// values[2]记录着手机围绕 Y 轴的旋转弧度。SensorManager.getOrientation(r, values);Log.e(TAG, "getValue R: " + Arrays.toString(r));Log.e(TAG, "getValue values: " + Arrays.toString(values));// 旋转弧度转为角度float pitch = (float) Math.toDegrees(values[0]);Log.e(TAG, "getValue pitch: "+ pitch);if (Math.abs(lastX) > 1.0) { // 设置条件防止频繁回调onOrientationListener.onOrientationChanged(pitch);}lastX = pitch;}public interface OnOrientationListener{void onOrientationChanged(float x);}public void setOnOrientationListener(OnOrientationListener onOrientationListener){this.onOrientationListener = onOrientationListener;Log.e(TAG, "setOnOrientationListener: 接口设置完成");}public MyOrientationListener(Context context){this.context=context;}public void onStart(){sensorManager = (SensorManager) context.getSystemService(SENSOR_SERVICE);if (sensorManager != null) { // 初始化两个传感器// getDefaultSensor:获取Sensor,使用给定的类型和唤醒属性返回传感器。magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);}if (magneticSensor != null) {assert sensorManager != null;sensorManager.registerListener(this, magneticSensor,SensorManager.SENSOR_DELAY_UI);}if (accelerometerSensor != null) {assert sensorManager != null;sensorManager.registerListener(this, accelerometerSensor,SensorManager.SENSOR_DELAY_UI);}}public void onStop(){sensorManager.unregisterListener(this); // 传感器解除绑定}
}
参考资料
传感器的相关知识讲的很详细
Android之传感器(三)方向传感器