Android感測器完全解析

風靈使發表於2019-01-07

什麼是感測器

維基百科是這樣定義的:感測器是一種物理裝置或生物器官,能夠探測、感受外界的訊號、物理條件(如光、熱、溼度)或化學組成(如煙霧),並將探知的資訊傳遞給其他裝置或器官。

常用感測器介紹與用法

Android平臺支援三個大類的感測器

  • Motion sensors(運動感測器)

這些感測器測量加速力,並沿三個軸的旋轉力。此類別包括加速度計,重力感應器, 陀螺儀和旋轉向量感測器。

  • Environmental sensors (環境感測器)

這些感測器測量各種環境引數,例如環境空氣溫度和壓力,照明和溼度。此類別包括氣壓計,光度計,和溫度計。

  • Position sensors (位置感測器)

這些感測器測量裝置的物理位置。這個類別包括方向感測器和磁力計。

感測器實現流程

第一步:得到SensorManager

SensorManager mSensorManager = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);

第二步:註冊感測器

Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
if (null != sensor)
mSensorManager.registerListener(this,sensor,SensorManager.SENSOR_DELAY_NORMAL);

registerListener這個方法有三個引數。

  • 第一個引數是感測器資料變化的監聽器

我們需要去實現SensorEventListener介面,他裡面有兩個回撥方法,

@Override  public void onSensorChanged(SensorEvent event) {   //當感測器的數值發生變化時呼叫  }  

@Override  public void onAccuracyChanged(Sensor sensor, int accuracy) {   //感測器的精度發生變化時呼叫  }

onSensorChanged方法只有一個SensorEvent型別的引數event,其中SensorEvent類有一個values變數非常重要,該變數的型別是float[]。但該變數最多隻有3個元素,而且根據感測器的不同,values變數中元素所代表的含義也不同。
關於values值的詳細含義請看參考文章!!!

  • 第二個引數是我們需要監聽的感測器
Sensor sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);

Sensor.TYPE_ACCELEROMETER則是Android設定感測器型別,這裡是指加速度感測器,

  • 第三個引數是感測器資料更新資料的速度

有以下四個值可選,他們的速度是遞增的

SENSOR_DELAY_UI
SENSOR_DELAY_NORMAL
SENSOR_DELAY_GAME
SENSOR_DELAY_FASTEST

感測器的登出

//登出所有感測器物件
public voidunregisterListener(SensorEventListener listener)

//登出指定的感測器物件
public voidunregisterListener(SensorEventListener listener, Sensor sensor)

sensor的獲取依舊是通過SensorManager.getDefaultSensor()方法。

獲得手機支援的所有感測器

Listsensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

Android感測器型別表

  • 加速度感測器:TYPE_ACCELEROMETER

m/s2測量它裝置所有三個物理軸線方向(x,y,和z)加速度。

  • 周圍溫度感測器:TYPE_AMBIENT_TEMPERATURE

檢測周圍空氣溫度。

  • 重力感測器:TYPE_GRAVITY

測量重力

  • 陀螺儀感測器:TYPE_GYROSCOPE

以rad/s測量裝置三個物理軸線方向(x,y,和z)。旋轉速度。

  • 光照感測器:TYPE_LIGHT

以lx測量周圍的光線級別。

  • 線性加速度感測器:TYPE_LINEAR_ACCELERATION

檢測沿著一個軸向的加速度。

  • 磁力感測器:TYPE_MAGNETIC_FIELD

測量周圍的三個物理軸線方向的磁場。

  • 方向感測器: TYPE_ORIENTATION

測量裝置所有三個物理軸線方向(x,y和x)的旋轉角度。

  • 壓力感測器:TYPE_PRESSURE

測量周圍空氣氣壓

  • 接近感測器:TYPE_PROXIMITY

檢測物體與手機的距離

  • 相對溼度感測器:TYPE_RELATIVE_HUMIDITY

檢測周圍空氣相對溼度

  • 旋轉向量感測器:TYPE_ROTATION_VECTOR

用於檢測運動和檢測旋轉。

  • 溫度感測器: TYPE_TEMPERATURE

檢測裝置的溫度

感測器使用實踐

這裡以方向感測器為例

方向感測器的獲取方式

Sensor sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);

上面這個,對,已經被google棄用了,瞭解就好。

Android中的座標系
這裡寫圖片描述

自己畫的有點醜,將就著看吧,Z軸預設垂直於地面,所謂獲取的三個Values陣列即對應手機與Z,Y,X形成的夾角,後面會說明,

前面說了,TYPE_ORIENTATION已被棄用,那麼最新的方向感測器是如何做的呢?

事實上,Android 獲取手機旋轉的方向和角度是通過加速度感測器和地磁感測器共同計算得出的

OK,我們這時候是需要同時使用兩個感測器的,看程式碼

Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
sensorManager.registerListener(listener, accelerometerSensor,SensorManager.SENSOR_DELAY_GAME);
sensorManager.registerListener(listener, magneticSensor,SensorManager.SENSOR_DELAY_GAME);

同時使用了加速度感測器和地磁感測器

獲取旋轉矩陣陣列R

SensorManager.getRotationMatrix(R, null, accelerometerValues, magneticValues);

獲取手機旋轉資料

SensorManager.getOrientation(R, values);

values 是一個長度為 3 的 float 陣列,手機在各個方向上的旋轉資料都會被存放到這個陣列當中。

對應關係:

values[0]->Z軸、values[1]->X軸、values[2]->Y軸

values[0]的取值範圍是-180180 度,其中±180 度表示正南方向,0 度表示正北方向,-90 度表示正西方向,90 度表示正東方向,如圖
這裡寫圖片描述

所謂,實踐是檢驗真理的唯一標準,這是我檢測後自行畫的,大家看一下就明白該怎麼根據獲取到的角度來做對應的處理了

一個完整的方向感測器封裝類

 public  class DirectionSensorUtils implements SensorEventListener {
 
        private SensorManager sensorManager;
        float[] accelerometerValues = new float[3];
        float[] magneticValues = new float[3];
        float lastRotateDegree;
        private ImageView compassImg;//指南針背景圖
 
        public DirectionSensorUtils(Context context , ImageView compassImg) {
            sensorManager = (SensorManager) context.getSystemService(Context.SENSOR_SERVICE);
            this.compassImg = compassImg;
        }
 
        //註冊感測器
        public void registerSensor(){
            Sensor accelerometerSensor = sensorManager.getDefaultSensor(Sensor.
                    TYPE_ACCELEROMETER);
            Sensor magneticSensor = sensorManager.getDefaultSensor(Sensor.
                    TYPE_MAGNETIC_FIELD);
            sensorManager.registerListener(this, accelerometerSensor,
                    SensorManager.SENSOR_DELAY_GAME);
            sensorManager.registerListener(this, magneticSensor,
                    SensorManager.SENSOR_DELAY_GAME);
        }
 
        //解除感測器註冊
        public void unregisterSensor(){
            if (sensorManager != null) {
                sensorManager.unregisterListener(this);
            }
        }
 
 
        @Override
        public void onSensorChanged(SensorEvent event) {
 
            // 判斷當前是加速度感測器還是地磁感測器
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                // 通過clone()獲取不同的values引用
                accelerometerValues = event.values.clone();
            } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                magneticValues = event.values.clone();
            }
 
            //獲取地磁與加速度感測器組合的旋轉矩陣
            float[] R = new float[9];
            float[] values = new float[3];
            SensorManager.getRotationMatrix(R, null, accelerometerValues,
                    magneticValues);
            SensorManager.getOrientation(R, values);
 
            //values[0]->Z軸、values[1]->X軸、values[2]->Y軸
            //使用前請進行轉換,因為獲取到的值是弧度,示例如下
            //        Math.toDegrees(values[0]);
            //        Math.toDegrees(values[1]);
            //        Math.toDegrees(values[2]);
 
 
            handleEvent(values);
 
        }
 
        public void handleEvent(float[] values){
 
            // 這裡實現了一個指南針
            float rotateDegree = -(float) Math.toDegrees(values[0]);
            if (Math.abs(rotateDegree - lastRotateDegree) > 1) {
                RotateAnimation animation = new RotateAnimation
                        (lastRotateDegree, rotateDegree, Animation.RELATIVE_TO_SELF, 0.5f, Animation.
                                RELATIVE_TO_SELF, 0.5f);
                animation.setFillAfter(true);
                compassImg.startAnimation(animation);
                lastRotateDegree = rotateDegree;
            }
        }
 
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
 
        }
    }

OK,還有其他很多感測器,但使用上大體一致,這裡將光照、加速度、方向感測器封住為了一個工具類,地址:https://github.com/walkthehorizon/UtilsSet/blob/master/UtilsLibrary/SensorUtils.java,如果對你有幫助歡迎fork、star以及issue,謝謝

相關文章