概述
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;
/** 当有新的传感器事件时(手机方向改变时调用)调用。 */
@Override
public 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();
}
/** 当注册传感器的精度发生变化时调用。 */
@Override
public 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); // 传感器解除绑定
}
}
参考资料
传感器的相关知识讲的很详细文章来源:https://www.toymoban.com/news/detail-404674.html
Android之传感器(三)方向传感器文章来源地址https://www.toymoban.com/news/detail-404674.html
到了这里,关于Android | Sensor.TYPE_ORIENTATION被废弃后的解决办法的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!