首頁 > 軟體

Android 如何獲取感測器的資料方法詳解

2022-07-29 14:03:38

1 感測器簡介

感測器 Sensor 是一種檢測裝置,能感受到被測量的資訊,並能將感受到的資訊,按一定規律變換成為電訊號或其他所需形式的資訊輸出,以滿足資訊的傳輸、處理、儲存、顯示、記錄和控制等要求。 Android 提供了對裝置感測器的支援,只要 Android 裝置的硬體提供了這些感測器,Android 應用可以通過感測器來獲取裝置的外界條件,包括手機的執行狀態、當前擺放的方向等。Android 系統還提供了驅動程式去管理這些感測器硬體,可以通過監聽器的方式監聽感測器硬體感知到的外部環境的變化。

Android 平臺支援三大類感測器:

類別感測器說明
運動感測器TYPE_ACCELEROMETER加速度感測器,基於硬體
TYPE_GRAVITY重力感測器,基於硬體或軟體
TYPE_GYROSCOPE陀螺儀感測器,基於硬體
TYPE_ROTATION_VECTOR旋轉向量感測器,基於硬體或軟體
TYPE_LINEAR_ACCELERATION線性加速度感測器,基於硬體或軟體
位置感測器TYPE_MAGNETIC_FIELD磁力感測器,基於硬體
TYPE_ORIENTATION方向感測器,基於軟體
TYPE_PROXIMITY距離感測器,基於硬體
環境感測器TYPE_LIGHT光線感應感測器,基於硬體
TYPE_PRESSURE壓力感測器,基於硬體
TYPE_TEMPERATURE溫度感測器,基於硬體

有些感測器基於硬體,有些基於軟體。基於硬體的感測器是內建在手機或平板裝置中的物理元件。這類感測器通過直接測量特定的環境屬性(如加速度、地磁場強度或角度變化)來採集資料。基於軟體的感測器不是物理裝置,它們只是模仿基於硬體的感測器。基於軟體的感測器從一個或多個基於硬體的感測器獲取資料,有時被稱為虛擬感測器或合成感測器。比如線性加速度感測器和重力感測器就是基於軟體的感測器。

感測器棄用說明:

  • Android 2.2(API 級別 8)已棄用方向感測器,Android 4.4W(API 級別 20)已棄用此感測器型別 TYPE_ORIENTATION。替代方法見後面範例程式碼。
  • 溫度感測器已在 Android 4.0(API 級別 14)中棄用,不同裝置具有不同的實現。

2 感測器的使用

2.1 獲取感測器服務

Android 中內建了很多系統級的服務,用於給開發人員使用,而感測器也是通過感測器服務 SensorManager 來管理的。而在 Android 元件中獲取系統服務,使用方法 Context.getSystemService(String) 即可,它的引數均以 static final 的方式定義在 Context 中,而獲取 SensorManager 需要傳入 Context.SENSOR_SERVICE。

SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);

2.2 獲取待監聽的感測器

感測器服務管理裝置上所有的感測器,所以需要獲取待監聽的感測器。 可以通過在 getSensorList() 方法中傳入 TYPE_ALL 來獲取裝置上的所有感測器:

List<Sensor> deviceSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);

也可以通過指定的 type 引數獲取到相對應的感測器,如果裝置上有多個特定型別的感測器,則必須將其中一個指定為預設感測器。如果沒有指定預設感測器,則該方法呼叫會返回 null,這表示裝置沒有該型別的感測器。

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

注意使用前先判斷感測器是否存在。

執行時檢測。

if (sensor != null) {
    //感測器存在
} else {
    //感測器不存在
}

使用清單檔案來限定目標裝置必須帶有指定感測器設定。

<uses-feature
    android:name="android.hardware.sensor.accelerometer"
    android:required="true" />

對於某一個感測器,它的一些具體資訊的獲取方法如下:

  • getMaximumRange() 最大取值範圍
  • getName() 裝置名稱
  • getPower() 功率
  • getResolution() 精度
  • getType() 感測器型別
  • getVentor() 裝置供應商
  • getVersion() 裝置版本號

2.3 註冊感測器的監聽器

獲得 SensorManager 和 Sensor 物件之後,就可以為其 Sensor 註冊監聽器了。為感測器註冊監聽器,使用 SensorManager.registerListener() 方法即可,它存在多個過載方法,但是有些方法已經過時了,下面提供一個常用的方法:

boolean registerListener(SensorEventListener listener,Sensor sensor,int rateUs)

上面方法引數的意義:listener:感測器的監聽器、sensor:待監聽的感測器、rateUs:感測器的取樣率。 從 registerListener() 方法可以看出,它需要傳遞一個 SensorEventListener 物件,它就是感測器的監聽器,其中包含兩個方法,需要開發人員去實現它:

  • void onSensorChanged(SensorEvent event):當感測器感應的值發生變化時回撥。
  • void onAccuracyChanged(Sensor sensor,int accuracy):當感測器精度發生變化時回撥。 對於上面兩個方法,感測器的精度一般是不會發生改變的,所以我們一般主要的程式碼量在 onSensorChanged()中。

在 onSensorChanged(SensorEvent event) 方法中有一個引數 event,通過 event 可以獲取感測器的型別以及感測器的資料。

  • 獲取感測器的型別:event.sensor.getType()
  • 獲取感測器的資料:event.values[i],i為0,1,2...,不同感測器,event.values[i] 對應的資料不同。以加速度感測器為例,values[0] 表示x軸上的加速度,values[1] 表示y軸上的加速度,values[2] 表示z軸上的加速度。

registerListener() 方法還有一個 rateUs 的引數,它表示監聽感測器改變的取樣率,就是從感測器獲取值的頻率。它被定義以 static final 的形式定義在 SensorManager 中,方便我們直接使用,它定義瞭如下幾個引數:

引數延時說明
SensorManager.SENSOR_DELAY_FASTEST0ms一般不是特別敏感的處理不推薦使用,該種模式可能造成手機電力大量消耗,由於傳遞的為原始資料,演演算法不處理好將會影響遊戲邏輯和 UI 的效能。
SensorManager.SENSOR_DELAY_GAME20ms一般絕大多數的實時性較高的遊戲都使用該級別。
SensorManager.SENSOR_DELAY_UI60ms適合普通使用者介面 UI 變化的頻率,相對節省電能和邏輯處理,一般遊戲開發中不使用。
SensorManager.SENSOR_DELAY_NORMAL200ms對於一般的益智類或 EASY 級別的遊戲可以使用,但過低的取樣率可能對一些賽車類遊戲有跳幀現象。

Android 為我們提供了這幾個取樣率的引數,方便我們使用。但對於選擇那種取樣率而言,並不是越快越好,要參照實際開發的應用的情況來說,取樣率越大,將越耗費資源,包括電量、CPU 等,所以要根據實際情況選擇,畢竟再強大的應用,如果造成裝置續航能力的降低,也是會被使用者所不喜的。

2.4 登出感測器的監聽器

當使用完感測器之後,需要為其登出監聽器,因為感測器的監聽器並不會因為應用的結束而自行釋放資源,需要開發人員在適當的時候主動登出。登出感測器監聽器使用 SensorManager.unregisterListener() 方法即可,和監聽器的註冊方法一樣,它也具有多個過載的方法,但是有一些已經被棄用了,下面介紹一個常用的:

void unregisterListener(SensorEventListener listener)

3 範例程式碼

Java 程式碼如下:

public class MainActivity extends AppCompatActivity {
    private final String TAG = "sensor-sample";
    private TextView mAccelerometerSensorTextView;
    private TextView mMagneticSensorTextView;
    private TextView mGyroscopeSensorTextView;
    private TextView mOrientationSensorTextView;
    private SensorManager mSensorManager;
    private MySensorEventListener mMySensorEventListener;
    private float[] mAccelerometerReading = new float[3];
    private float[] mMagneticFieldReading = new float[3];
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mAccelerometerSensorTextView = findViewById(R.id.accelerometer_sensor);
        mMagneticSensorTextView = findViewById(R.id.magnetic_sensor);
        mGyroscopeSensorTextView = findViewById(R.id.gyroscope_sensor);
        mOrientationSensorTextView = findViewById(R.id.orientation_sensor);

        this.mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
        this.mMySensorEventListener = new MySensorEventListener();
    }
    @Override
    protected void onResume() {
        super.onResume();
        if (mSensorManager == null) {
            return;
        }
        Sensor accelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (accelerometerSensor != null) {
            //register accelerometer sensor listener
            mSensorManager.registerListener(mMySensorEventListener, accelerometerSensor, SensorManager.SENSOR_DELAY_UI);
        } else {
            Log.d(TAG, "Accelerometer sensors are not supported on current devices.");
        }
        Sensor magneticSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
        if (magneticSensor != null) {
            //register magnetic sensor listener
            mSensorManager.registerListener(mMySensorEventListener, magneticSensor, SensorManager.SENSOR_DELAY_UI);
        } else {
            Log.d(TAG, "Magnetic sensors are not supported on current devices.");
        }
        Sensor gyroscopeSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
        if (gyroscopeSensor != null) {
            //register gyroscope sensor listener
            mSensorManager.registerListener(mMySensorEventListener, gyroscopeSensor, SensorManager.SENSOR_DELAY_UI);
        } else {
            Log.d(TAG, "Gyroscope sensors are not supported on current devices.");
        }
    }
    @Override
    protected void onPause() {
        super.onPause();
        if (mSensorManager == null) {
            return;
        }
        //unregister all listener
        mSensorManager.unregisterListener(mMySensorEventListener);
    }

    /*
    This orientation sensor was deprecated in Android 2.2 (API level 8), and this sensor type was deprecated in Android 4.4W (API level 20).
    The sensor framework provides alternate methods for acquiring device orientation.
     */
    private void calculateOrientation() {
        final float[] rotationMatrix = new float[9];
        SensorManager.getRotationMatrix(rotationMatrix, null, mAccelerometerReading, mMagneticFieldReading);

        final float[] orientationAngles = new float[3];
        SensorManager.getOrientation(rotationMatrix, orientationAngles);
        Log.d(TAG, "orientation data[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
        mOrientationSensorTextView.setText("[x:" + orientationAngles[0] + ", y:" + orientationAngles[1] + ", z:" + orientationAngles[2] + "]");
    }
    private class MySensorEventListener implements SensorEventListener {
        @Override
        public void onSensorChanged(SensorEvent event) {
            if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
                mAccelerometerReading = event.values;
                Log.d(TAG, "accelerometer data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
                mAccelerometerSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
            } else if (event.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD) {
                mMagneticFieldReading = event.values;
                Log.d(TAG, "magnetic data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
                mMagneticSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
            } else if (event.sensor.getType() == Sensor.TYPE_GYROSCOPE) {
                Log.d(TAG, "gyroscope data[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
                mGyroscopeSensorTextView.setText("[x:" + event.values[0] + ", y:" + event.values[1] + ", z:" + event.values[2] + "]");
            }
            calculateOrientation();
        }
        @Override
        public void onAccuracyChanged(Sensor sensor, int accuracy) {
            Log.d(TAG, "onAccuracyChanged:" + sensor.getType() + "->" + accuracy);
        }

    }
}

執行效果如下:

到此這篇關於Android 如何獲取感測器的資料的文章就介紹到這了,更多相關Android 獲取感測器內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com