【Sensors】傳感器概述(2)

大多數基於Android的設備都具有內置傳感器,可以測量運動,方向和各種環境條件。這些傳感器能夠提供高精度和高精度的原始數據,如果您想要監測三維設備移動或定位,或者想要監視設備附近周圍環境的變化,這些傳感器非常有用。例如,遊戲可以跟蹤來自設備的重力傳感器的讀數以推斷複雜的用戶手勢和運動,諸如傾斜,搖晃,旋轉或搖擺。同樣,天氣應用可以使用設備的溫度傳感器和溼度傳感器來計算和報告露點,或者旅行應用可以使用地磁場傳感器和加速計來報告指南針的方位。

請參閱以下相關資源:

Android平臺支持三大類傳感器:

運動傳感器
這些傳感器測量沿三個軸的加速力和旋轉力。該類別包括加速度計,重力傳感器,陀螺儀和旋轉矢量傳感器。

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

位置傳感器
這些傳感器測量設備的物理位置。該類別包括方向傳感器和磁力計。

您可以使用Android傳感器框架訪問設備上可用的傳感器並獲取原始傳感器數據。傳感器框架提供了幾個類別和接口,可幫助您執行各種與傳感器相關的任務。例如,您可以使用傳感器框架執行以下操作:

  • 確定設備上有哪些傳感器可用。
  • 確定單個傳感器的功能,例如其最大範圍,製造商,功率要求和分辨率。
  • 獲取原始傳感器數據並定義您獲取傳感器數據的最小速率。
  • 註冊和取消註冊監控傳感器變化的傳感器事件監聽器。
    本主題概述了Android平臺上可用的傳感器。它還介紹了傳感器框架。

傳感器簡介


Android傳感器框架可讓您訪問多種類型的傳感器。其中一些傳感器基於硬件,一些基於軟件。基於硬件的傳感器是內置於手機或平板電腦設備中的物理組件。他們通過直接測量具體的環境屬性(如加速度,地磁場強度或角度變化)來獲取數據。基於軟件的傳感器不是物理設備,儘管它們模仿基於硬件的傳感器。基於軟件的傳感器從一個或多個基於硬件的傳感器獲取數據,有時稱爲虛擬傳感器或合成傳感器。線性加速度傳感器和重力傳感器是基於軟件的傳感器的示例。表1總結了Android平臺支持的傳感器。

幾乎沒有Android設備的設備擁有各種類型的傳感器。例如,大多數手機設備和平板電腦都有加速度計和磁力計,但更少的設備有氣壓計或溫度計。此外,一個設備可以有多個給定類型的傳感器。例如,一個設備可以有兩個重力傳感器,每個重力傳感器具有不同的範圍。

表1. Android平臺支持的傳感器類型。
【Sensors】傳感器概述(2)
【Sensors】傳感器概述(2)

傳感器框架

您可以使用Android傳感器框架訪問這些傳感器並獲取原始傳感器數據。傳感器框架是android.hardware軟件包的一部分,包括以下類和接口:

SensorManager
您可以使用此類創建傳感器服務的實例。該課程提供了訪問和列出傳感器,註冊和註銷傳感器事件監聽器以及獲取方向信息的各種方法。該類還提供了幾個傳感器常量,用於報告傳感器的準確性,設置數據採集速率和校準傳感器。

Sensor
您可以使用此類創建特定傳感器的實例。該課程提供了各種方法,可以讓您確定傳感器的功能。

SensorEvent
系統使用此類創建傳感器事件對象,該對象提供有關傳感器事件的信息。傳感器事件對象包含以下信息:原始傳感器數據,生成事件的傳感器類型,數據的準確性以及事件的時間戳。

SensorEventListener
您可以使用此界面創建兩種回傳方法,在傳感器值更改或傳感器準確度更改時接收通知(傳感器事件)。
在典型的應用中,您使用這些傳感器相關的API來執行兩項基本任務:

識別傳感器和傳感器功能
如果您的應用程序具有依賴於特定傳感器類型或功能的功能,則在運行時識別傳感器和傳感器功能非常有用。例如,您可能需要識別設備上存在的所有傳感器,並禁用依賴於不存在的傳感器的任何應用程序功能。同樣,您可能需要識別給定類型的所有傳感器,以便您可以選擇對應用具有最佳性能的傳感器實施。

監視傳感器事件
監測傳感器事件是如何獲取原始傳感器數據。每當傳感器檢測到正在測量的參數發生變化時,就會發生傳感器事件。傳感器事件爲您提供了四條信息:觸發事件的傳感器名稱,事件的時間戳,事件的準確性以及觸發事件的原始傳感器數據。

傳感器可用性

雖然每個設備的傳感器可用性不同,但Android版本的傳感器可用性也不盡相同。這是因爲Android傳感器已經在幾個平臺發佈的過程中引入。例如,Android 1.5(API Level 3)中引入了許多傳感器,但有些未實現,直到Android 2.3(API Level 9)才能使用。同樣,在Android 2.3(API等級9)和Android 4.0(API等級14)中引入了幾個傳感器。兩個傳感器已被棄用,並被更新,更好的傳感器取代。

表2總結了每個平臺上每個傳感器的可用性。僅列出四個平臺,因爲這些平臺涉及傳感器更改。列爲已棄用的傳感器在後續平臺上仍可用(前提是傳感器存在於設備上),這符合Android的前向兼容性策略。
表2.平臺的傳感器可用性。
【Sensors】傳感器概述(2)
1此傳感器類型已添加到Android 1.5(API Level 3)中,但直到Android 2.3(API Level 9)才能使用。
2該傳感器可用,但已被棄用。

識別傳感器和傳感器功能


Android傳感器框架提供了幾種方法,使您可以輕鬆地在運行時確定設備上的哪些傳感器。該API還提供了一些方法,可以讓您確定每個傳感器的功能,例如其最大範圍,分辨率和功率要求。

要識別設備上的傳感器,首先需要參考傳感器服務。爲此,SensorManager通過調用getSystemService()方法並傳入SENSOR_SERVICE參數來創建類的實例。例如:

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

接下來,您可以通過調用該getSensorList()方法並使用該TYPE_ALL常量來獲取設備上每個傳感器的列表 。例如:

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

如果要列出特定類型的傳感器,可以使用另一種恆定的,而不是 TYPE_ALL如TYPE_GYROSCOPE, TYPE_LINEAR_ACCELERATION或 TYPE_GRAVITY。

您還可以通過使用該getDefaultSensor()方法並傳入特定傳感器的類型常量來確定設備上是否存在特定類型的傳感器。如果設備具有多個給定類型的傳感器,則必須將其中一個傳感器指定爲默認傳感器。如果給定類型的傳感器不存在默認傳感器,則方法調用返回null,這意味着設備沒有該類型的傳感器。例如,以下代碼檢查設備上是否有磁力計:

private SensorManager mSensorManager;
...
mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
if (mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) != null){
  // Success! There's a magnetometer.
  }
else {
  // Failure! No magnetometer.
  }

注意: Android不要求設備製造商在Android設備中構建任何特定類型的傳感器,因此設備可以有多種傳感器配置。

除列出設備上的傳感器外,您還可以使用Sensor該類的公共方法 來確定各個傳感器的功能和屬性。如果您希望應用程序根據設備上可用的傳感器或傳感器功能的不同而有所不同,則此功能非常有用。例如,您可以使用getResolution()和getMaximumRange() 方法來獲取傳感器的分辨率和最大測量範圍。您也可以使用該 getPower()方法獲取傳感器的功率要求。

如果您想針對不同製造商的傳感器或不同版本的傳感器優化您的應用,兩種公共方法特別有用。例如,如果您的應用程序需要監視諸如傾斜和晃動之類的用戶手勢,則可以爲具有特定供應商重力感應器的較新設備創建一組數據過濾規則和優化,併爲設備創建另一組數據過濾規則和優化沒有重力傳感器,只有一個加速度計。以下代碼示例顯示如何使用getVendor()和getVersion()方法來執行此操作。在本示例中,我們正在尋找將LLC LLC列爲供應商的重力感應器,其版本號爲3.如果該設備上沒有特定的傳感器,我們會嘗試使用加速度計。

private SensorManager mSensorManager;
private Sensor mSensor;

...

mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
mSensor = null;

if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
  List<Sensor> gravSensors = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY);
  for(int i=0; i<gravSensors.size(); i++) {
    if ((gravSensors.get(i).getVendor().contains("Google LLC")) &&
       (gravSensors.get(i).getVersion() == 3)){
      // Use the version 3 gravity sensor.
      mSensor = gravSensors.get(i);
    }
  }
}
if (mSensor == null){
  // Use the accelerometer.
  if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
    mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
  }
  else{
    // Sorry, there are no accelerometers on your device.
    // You can't play this game.
  }
}

另一種有用的方法是getMinDelay()返回傳感器可用於檢測數據的最小時間間隔(以微秒爲單位)。任何爲該方法返回非零值的getMinDelay() 傳感器都是流傳感器。流傳感器定期檢測數據,並在Android 2.3(API Level 9)中引入。如果調用該getMinDelay()方法時傳感器歸零,則表示該傳感器不是流傳感器,因爲它只在傳感參數發生變化時纔會報告數據。

該getMinDelay()方法非常有用,因爲它可以讓您確定傳感器可以採集數據的最大速率。如果應用程序中的某些功能需要高數據採集速率或流式傳感器,則可以使用此方法確定傳感器是否滿足這些要求,然後相應地啓用或禁用應用程序中的相關功能。

警告:傳感器的最大數據採集率不一定是傳感器框架將傳感器數據傳送到應用程序的速率。傳感器框架通過傳感器事件報告數據,並且幾個因素影響應用程序接收傳感器事件的速率。有關更多信息,請參閱監控傳感器事件。

監測傳感器事件


要監視原始傳感器數據,您需要實現兩個通過SensorEventListener接口公開的回調方法:onAccuracyChanged()和onSensorChanged()。發生以下情況時,Android系統會調用這些方法:

傳感器的準確度發生變化。
在這種情況下,系統調用該onAccuracyChanged()方法,爲您提供對Sensor已更改對象的參考以及傳感器的新準確度。:精度由四個狀態常數之一表示 SENSOR_STATUS_ACCURACY_LOW, SENSOR_STATUS_ACCURACY_MEDIUM, SENSOR_STATUS_ACCURACY_HIGH,或SENSOR_STATUS_UNRELIABLE。

傳感器報告一個新值。
在這種情況下,系統調用該onSensorChanged()方法,爲您提供一個SensorEvent對象。甲SensorEvent對象包含有關新的傳感器數據的信息,包括:所述數據的準確度,即所產生的數據,在該生成數據的時間戳,並且新數據記錄在傳感器的傳感器。

以下代碼顯示瞭如何使用該onSensorChanged()方法監測光傳感器的數據。此示例顯示TextView 在main.xml文件中定義的原始傳感器數據sensor_data。

public class SensorActivity extends Activity implements SensorEventListener {
  private SensorManager mSensorManager;
  private Sensor mLight;

  @Override
  public final void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
    mLight = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
  }

  @Override
  public final void onAccuracyChanged(Sensor sensor, int accuracy) {
    // Do something here if sensor accuracy changes.
  }

  @Override
  public final void onSensorChanged(SensorEvent event) {
    // The light sensor returns a single value.
    // Many sensors return 3 values, one for each axis.
    float lux = event.values[0];
    // Do something with this sensor value.
  }

  @Override
  protected void onResume() {
    super.onResume();
    mSensorManager.registerListener(this, mLight, SensorManager.SENSOR_DELAY_NORMAL);
  }

  @Override
  protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(this);
  }
}

在這個例子中,默認數據delay(SENSOR_DELAY_NORMAL)是在registerListener()調用方法時指定的。數據延遲(或採樣率)控制傳感器事件通過onSensorChanged()回調方法發送到應用程序的時間間隔。默認數據延遲適用於監視典型的屏幕方向更改,並使用200,000微秒的延遲。您可以指定其他數據延遲,例如SENSOR_DELAY_GAME(20,000微秒延遲),SENSOR_DELAY_UI(60,000微秒延遲)或SENSOR_DELAY_FASTEST(0微秒延遲)。從Android 3.0(API Level 11)開始,您還可以將延遲指定爲絕對值(以微秒爲單位)。

您指定的延遲只是建議的延遲。Android系統和其他應用程序可以改變這種延遲。作爲最佳做法,您應該指定最大的延遲時間,因爲系統通常使用的延遲比您指定的延遲時間要短(即應選擇仍然滿足應用程序需求的最慢採樣率)。使用較大的延遲會對處理器造成較低的負載,因此功耗較低。

沒有公開的方法來確定傳感器框架嚮應用程序發送傳感器事件的速率; 但是,您可以使用與每個傳感器事件關聯的時間戳來計算多個事件的採樣率。設置後,您不必改變採樣率(延遲)。如果由於某些原因您確實需要更改延遲時間,則必須取消註冊並重新註冊傳感器偵聽器。

注意到這個例子使用onResume()和 onPause()回調方法來註冊和取消註冊傳感器事件偵聽器也很重要。作爲最佳做法,您應該始終禁用不需要的傳感器,尤其是當您的活動暫停時。如果不這樣做,可能會在幾個小時內耗盡電池,因爲某些傳感器具有相當大的功率要求,並且可能會迅速耗盡電池電量。屏幕關閉時,系統不會自動禁用傳感器。

處理不同的傳感器配置


Android並未爲設備指定標準傳感器配置,這意味着設備製造商可以將他們想要的任何傳感器配置合併到其支持Android的設備中。因此,設備可以包含多種配置的各種傳感器。如果您的應用程序依賴於特定類型的傳感器,則必須確保傳感器存在於設備上,以便您的應用程序可以成功運行。

您有兩種選擇來確保設備上存在指定的傳感器:

  • 在運行時檢測傳感器,並根據需要啓用或禁用應用程序功能。
  • 使用Google Play過濾器定位具有特定傳感器配置的設備。

以下各節將討論每個選項。

在運行時檢測傳感器
如果您的應用程序使用特定類型的傳感器,但不依賴它,則可以使用傳感器框架在運行時檢測傳感器,然後根據需要禁用或啓用應用程序功能。例如,導航應用可以使用溫度傳感器,壓力傳感器,GPS傳感器和地磁場傳感器來顯示溫度,氣壓,位置和羅盤方位。如果設備沒有壓力傳感器,則可以使用傳感器框架在運行時檢測壓力傳感器的不存在情況,然後禁用顯示壓力的應用程序UI部分。例如,以下代碼檢查設備上是否有壓力傳感器:

  private SensorManager mSensorManager;
  ...
  mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
  if (mSensorManager.getDefaultSensor(Sensor.TYPE_PRESSURE) != null){
  // Success! There's a pressure sensor.
  }
  else {
  // Failure! No pressure sensor.
  }

使用Google Play過濾器定位特定的傳感器配置
如果您在Google Play上發佈您的應用程序,則可以使用<uses-feature> 清單文件中的 元素來過濾來自沒有適用於您應用程序的傳感器配置的設備的應用程序。該 <uses-feature>元素具有多個硬件描述符,可讓您根據特定傳感器的存在來過濾應用程序。您可以列出的傳感器包括:加速度計,氣壓計,指南針(地磁場),陀螺儀,光線和接近度。以下是一個示例清單條目,用於過濾沒有加速計的應用程序:

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

如果您將此元素和描述符添加到應用程序的清單中,則僅當用戶的設備具有加速度計時,用戶纔會在Google Play上看到您的應用程序。

android:required="true"只有當您的應用程序完全依賴於特定的傳感器時,才應該將描述符設置爲。如果您的應用程序使用某個功能的傳感器,但仍然在沒有傳感器的情況下運行,您應該將傳感器列在<uses-feature> 元素中,但將描述符設置爲android:required="false"。這有助於確保設備可以安裝您的應用程序,即使它們沒有特定的傳感器。這也是項目管理的最佳實踐,可幫助您跟蹤應用程序使用的功能。請記住,如果您的應用程序使用特定的傳感器,但仍然在沒有傳感器的情況下運行,那麼您應該在運行時檢測傳感器,並根據需要禁用或啓用應用程序功能。

傳感器座標系統


通常,傳感器框架使用標準的3軸座標系來表示數據值。對於大多數傳感器而言,座標系統是相對於設備的屏幕定義的,當設備保持其默認方向時(參見圖1)。當設備保持其默認方向時,X軸是水平的並指向右側,Y軸是垂直的並指向上方,而Z軸指向屏幕表面的外側。在這個系統中,屏幕後面的座標具有負Z值。這個座標系被以下傳感器使用:

  • 加速度傳感器
  • 重力傳感器
  • 陀螺儀
  • 線性加速度傳感器
  • 地磁場傳感器
    【Sensors】傳感器概述(2)
    圖1.傳感器API使用的座標系(相對於設備)。

瞭解這個座標系最重要的一點是,當設備的屏幕方向改變時,軸不會交換 - 也就是說,傳感器的座標系不會隨設備移動而改變。這種行爲與OpenGL座標系統的行爲相同。

需要理解的另一點是,您的應用程序不得假定設備的自然(默認)方向是縱向。許多平板設備的自然定位是風景。傳感器座標系始終基於設備的自然方向。

最後,如果您的應用程序將傳感器數據與屏幕顯示相匹配,則需要使用該 getRotation()方法確定屏幕旋轉,然後使用該 remapCoordinateSystem()方法將傳感器座標映射到屏幕座標。即使您的清單指定了僅限肖像的顯示,您也需要執行此操作。

注意:某些傳感器和方法使用與世界參照系相關的座標系(與設備的參照系相反)。這些傳感器和方法返回代表設備運動或設備相對於地球位置的數據。有關更多信息,請參閱getOrientation()方法,getRotationMatrix()方法,方向傳感器和旋轉矢量傳感器。

訪問和使用傳感器的最佳實踐


在設計傳感器實施時,請務必遵循本節中討論的準則。對於使用傳感器框架訪問傳感器並獲取傳感器數據的任何人,建議使用這些準則的最佳做法。

取消註冊傳感器偵聽器
當您使用傳感器或傳感器活動暫停時,請務必註銷傳感器的聽衆。如果傳感器偵聽器已註冊並且其活動已暫停,則傳感器將繼續獲取數據並使用電池資源,除非您註銷傳感器。以下代碼顯示如何使用該onPause()方法註銷偵聽器:

private SensorManager mSensorManager;
  ...
@Override
protected void onPause() {
  super.onPause();
  mSensorManager.unregisterListener(this);
}

有關更多信息,請參閱unregisterListener(SensorEventListener)。

使用Android模擬器進行測試
Android模擬器包含一組虛擬傳感器控件,可用於測試傳感器,如加速度計,環境溫度,磁力計,接近度,光線等。

【Sensors】傳感器概述(2)
模擬器使用與運行SdkControllerSensor 應用程序的Android設備的連接 。請注意,此應用僅適用於運行Android 4.0(API級別14)或更高版本的設備。(如果設備運行的是Android 4.0,則必須安裝修訂版2.)SdkControllerSensor應用程序監視設備上傳感器的更改並將其傳輸到仿真器。然後根據設備上的傳感器接收到的新值對仿真器進行轉換。

您可以在以下位置查看SdkControllerSensor應用程序的源代碼:

$ your-android-sdk-directory/tools/apps/SdkController

要在您的設備和模擬器之間傳輸數據,請按照以下步驟操作:

  1. 檢查您的設備上是否啓用了USB調試。
  2. 使用USB電纜將設備連接到開發機器。
  3. 在設備上啓動SdkControllerSensor應用程序。
  4. 在應用程序中,選擇您想要模擬的傳感器。
  5. 運行以下adb命令:
$ adb forward tcp:1968 tcp:1968

啓動模擬器。您現在應該可以通過移動設備將轉換應用到模擬器。

注意:如果您對物理設備所做的移動不會改變仿真器,請嘗試再次運行adb步驟5中的 命令。

有關更多信息,請參閱Android模擬器指南

不要阻止onSensorChanged()方法
傳感器數據可以高速更改,這意味着系統可能會onSensorChanged(SensorEvent)經常調用該方法。作爲一種最佳實踐,您應該儘可能少地使用該onSensorChanged(SensorEvent)方法,以免造成阻礙。如果您的應用程序要求您執行任何數據過濾或減少傳感器數據,則應該在onSensorChanged(SensorEvent)方法之外執行該工作。

避免使用不推薦使用的方法或傳感器類型
一些方法和常量已被棄用。特別是,TYPE_ORIENTATION 傳感器類型已被棄用。要獲得方向數據,您應該使用該getOrientation()方法。同樣, TYPE_TEMPERATURE傳感器類型已被棄用。您應該TYPE_AMBIENT_TEMPERATURE在運行Android 4.0的設備上使用傳感器類型。

在使用它們之前驗證傳感器
在嘗試從設備獲取數據之前,請始終驗證設備上是否存在傳感器。不要以爲傳感器是一種常用的傳感器,而是假定傳感器存在。設備製造商不需要在其設備中提供任何特定的傳感器。

仔細選擇傳感器延遲
當您使用該registerListener()方法註冊傳感器時,請確保您選擇適合您的應用或用例的傳輸速率。傳感器可以以非常高的速率提供數據。允許系統發送您不需要的額外數據會浪費系統資源並使用電池電量。

Lastest Update:2018.04.24

聯繫我

QQ:94297366
微信打賞:https://pan.baidu.com/s/1dSBXk3eFZu3mAMkw3xu9KQ

公衆號推薦:

【Sensors】傳感器概述(2)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章