Android | Sensor.TYPE_ORIENTATION被废弃后的解决办法


概述

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 方法的介绍如下:
在这里插入图片描述
该函数有两个参数,Rvalues。传入时 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 方法的介绍如下:
在这里插入图片描述
该函数有四个参数,通过计算 gravitygeomagnetic 得到 旋转矩阵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); // 传感器解除绑定
    }
}

参考资料

传感器的相关知识讲的很详细

Android之传感器(三)方向传感器

猜你喜欢

转载自blog.csdn.net/Jormungand_V/article/details/124721434