西部数码主机 | 阿里云主机| 虚拟主机 | 服务器 | 返回乐道官网

Sensor和SensorManager实现重力和方向

时间:2016-02-07 21:22来源:未知 作者:好模板 点击:
一.Android中检测重力感应变化大致需要下面几个步骤: 1.得到传感器服务 getSystemService(SENSOR_SERVICE); 2.得到传感器类型getDefaultSensor(Sensor.TYPE_GRAVITY); 3.注册监听器 SensorEventListener; 4. 实现

一.Android中检测重力感应变化大致需要下面几个步骤:

1.得到传感器服务 getSystemService(SENSOR_SERVICE);
2.得到传感器类型getDefaultSensor(Sensor.TYPE_GRAVITY);
3.注册监听器 SensorEventListener;
4. 实现监听器的回调函数 onSensorChanged, onAccuracyChanged;

二. 常用的感应器

1.获取加速度: 加速度感应器

可以通过这个感应器获得三个浮点型
x-axisy-axis
z-axis
可参阅《android 高级编程2》中的一个插图分析次数据


X Y Z分别对应values[0]到[2]
X表示左右移动的加速度
Y表示前后移动的加速度
Z表示垂直方向的加速度

public class MainActivity extends AppCompatActivity {

    //设置LOG标签
    private static final String TAG = "sensor";
    private SensorManager sm;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //1.创建一个SensorManager来获取系统的传感器服务
        sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        //2.选取加速度感应器
        int sensorType = Sensor.TYPE_ACCELEROMETER;

        /*
         * 最常用的一个方法 注册事件
         * 参数1 :SensorEventListener监听器
         * 参数2 :Sensor 一个服务可能有多个Sensor实现,此处调用getDefaultSensor获取默认的Sensor
         * 参数3 :模式 可选数据变化的刷新频率
         * */
        sm.registerListener(myAccelerometerListener, sm.getDefaultSensor(sensorType), SensorManager.SENSOR_DELAY_NORMAL);

    }

    /*
     * 3.SensorEventListener接口的实现,需要实现两个方法
     * 方法1 onSensorChanged 当数据变化的时候被触发调用
     * 方法2 onAccuracyChanged 当获得数据的精度发生变化的时候被调用,比如突然无法获得数据时
     * */
    final SensorEventListener myAccelerometerListener = new SensorEventListener() {

        //4.复写onSensorChanged方法
        public void onSensorChanged(SensorEvent sensorEvent) {
            if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                Log.i(TAG, "onSensorChanged");

                //图解中已经解释三个值的含义
                float X_lateral = sensorEvent.values[0];
                float Y_longitudinal = sensorEvent.values[1];
                float Z_vertical = sensorEvent.values[2];
                Log.i(TAG, "\n heading " + X_lateral);
                Log.i(TAG, "\n pitch " + Y_longitudinal);
                Log.i(TAG, "\n roll " + Z_vertical);
            }
        }

        //复写onAccuracyChanged方法
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            Log.i(TAG, "onAccuracyChanged");
        }
    };

    public void onPause() {
        /*
         * 很关键的部分:注意,说明文档中提到,即使activity不可见的时候,感应器依然会继续的工作,测试的时候可以发现,没有正常的刷新频率
         * 也会非常高,所以一定要在onPause方法中关闭触发器,否则讲耗费用户大量电量,很不负责。
         * */
        sm.unregisterListener(myAccelerometerListener);
        super.onPause();
    }
}

2.获取用户移动方向:方向感应器

android给我们提供的方向数据是一个float型的数组,包含三个方向的值如图


当你的手机水平放置时,被默认为静置状态,即XY角度均为0
values[0] 表示Z轴的角度:方向角,我们平时判断的东西南北就是看这个数据的,经过我的实验,发现了一个有意思的事情,也就是说使用第一种方式获得方向(磁场+加速度)得到的数据范围是(-180~180),也就是说,0表示正北,90表示正东,180/-180表示正南,-90表示正西。而第二种方式(直接通过方向感应器)数据范围是(0~360)360/0表示正北,90表示正东,180表示正南,270表示正西。
values[1] 表示X轴的角度:俯仰角 即由静止状态开始,前后翻转
values[2] 表示Y轴的角度:翻转角 即由静止状态开始,左右翻转

public static boolean getRotationMatrix(float[] R, float[] I, float[] gravity, float[] geomagnetic)
R[] 是一个旋转矩阵,用来保存磁场和加速度的数据,大家可以理解未加工的方向数据吧
R通过下面的静态方法获取,这个方法也是用来填充R[]
getRotationMatrix中的参数:
第一个就是我们需要填充的R数组,大小是9
第二个是是一个转换矩阵,将磁场数据转换进实际的重力坐标中 一般默认情况下可以设置为null
第三个是一个大小为3的数组,表示从加速度感应器获取来的数据 在onSensorChanged中
第四个是一个大小为3的数组,表示从磁场感应器获取来的数据 在onSensorChanged中
------------------这是一条分割线管你看不看╭(╯^╰)╮------------------
代码:

public class MainActivity extends AppCompatActivity {

    private static final String TAG = "sensor";
    //1.得到传感器
    private SensorManager sm;
    //需要两个Sensor
    private Sensor aSensor;
    private Sensor mSensor;

    float[] accelerometerValues = new float[3];
    float[] magneticFieldValues = new float[3];

    @Override
    public void onCreate(Bundle savedInstanceState) {
        // TODO Auto-generated method stub
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
          //1.得到传感器服务getSystemService(SENSOR_SERVICE);
        sm = (SensorManager)getSystemService(Context.SENSOR_SERVICE);
          //2.得到传感器类型getDefaultSensor(Sensor.TYPE_GRAVITY);
        aSensor = sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        mSensor = sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        //注册监听
        sm.registerListener(myListener, aSensor, SensorManager.SENSOR_DELAY_NORMAL);
        sm.registerListener(myListener, mSensor,SensorManager.SENSOR_DELAY_NORMAL);
        //更新显示数据的方法
        calculateOrientation();

    }
    //再次强调:注意activity暂停的时候释放
    public void onPause(){
        sm.unregisterListener(myListener);
        super.onPause();
    }

//3.注册监听器 SensorEventListener
    final SensorEventListener myListener = new SensorEventListener() {
    //4. 实现监听器的回调函数 onSensorChanged, onAccuracyChanged
        public void onSensorChanged(SensorEvent sensorEvent) {

            if (sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD)
                magneticFieldValues = sensorEvent.values;
            if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER)
                accelerometerValues = sensorEvent.values;
            calculateOrientation();
        }
        public void onAccuracyChanged(Sensor sensor, int accuracy) {}
    };

    /**
     * 计算方向
     */
    private  void calculateOrientation() {
        float[] values = new float[3];
        float[] R = new float[9];
        SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticFieldValues);
        SensorManager.getOrientation(R, values);

        // 要经过一次数据格式的转换,转换为度
        values[0] = (float) Math.toDegrees(values[0]);
        Log.i(TAG, values[0] + "");
        //values[1] = (float) Math.toDegrees(values[1]);
        //values[2] = (float) Math.toDegrees(values[2]);

        if(values[0] >= -5 && values[0] < 5){
            Log.i(TAG, "正北");
        }
        else if(values[0] >= 5 && values[0] < 85){
            Log.i(TAG, "东北");
        }
        else if(values[0] >= 85 && values[0] <=95){
            Log.i(TAG, "正东");
        }
        else if(values[0] >= 95 && values[0] <175){
            Log.i(TAG, "东南");
        }
        else if((values[0] >= 175 && values[0] <= 180) || (values[0]) >= -180 && values[0] < -175){
            Log.i(TAG, "正南");
        }
        else if(values[0] >= -175 && values[0] <-95){
            Log.i(TAG, "西南");
        }
        else if(values[0] >= -95 && values[0] < -85){
            Log.i(TAG, "正西");
        }
        else if(values[0] >= -85 && values[0] <-5){
            Log.i(TAG, "西北");
        }
    }
}

打印日志:


打印日志

特别注意:

在Activity暂定的时候,要关闭感应器。不然会很耗电。

(责任编辑:好模板)
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
栏目列表
热点内容