關于Android傳感器

最近項目需要各種手機傳感器,于是就此來寫個總結,以此留痕。
在Android開發中,會用到各種傳感器,但不一定每個真機都支持這些傳感器。所以相關開發還要根據真機的實際情況來做開發。
1 獲取手機的傳感器
通過實例化SensorManager可以獲取到手機的傳感器集合

//實例化
mSensorManger= (SensorManager) getSystemService(Context.SENSOR_SERVICE);
List<Sensor> sensorList = mSensorManger.getSensorList(Sensor.TYPE_ALL);

獲取到的傳感器名稱:
Accelerometer 加速計
Magnetometer 磁力計
Gyroscope 陀螺儀
Proximity Sensor 近距離傳感器
Ambient Light Sensor 環境光傳感器
Barometer Sensor 氣壓計
Temperature Sensor 溫度傳感器
Gravity 重力
Linear Acceleration 線性加速度
Rotation Vector 旋轉矢量
Step Detector 步數探測器
Step Counter 計步器
Significant Motion Detector 運動檢測器
Game Rotation Vector 游戲旋轉矢量
Geomagnetic Rotation Vector 地磁旋轉矢量
Orientation 方向
Basic Gestures 基本手勢
Motion Accel 運動加速度

Android傳感器按大方向劃分大致有這么三類傳感器:動作(Motion)傳感器、環境(Environmental)傳感器、位置(Position)傳感器。
(1)動作傳感器
這類傳感器在三個軸(x、y、z)上測量加速度和旋轉角度。包括如下幾個傳感器:

加速(accelerometer)傳感器、重力(gravity)傳感器、陀螺儀(gyroscope)傳感器、旋轉向量(rotational vector )傳感器
下面來看一下傳感器世界的坐標系:
[圖片上傳失敗...(image-a8a3de-1567500246575)]
(2)環境傳感器
這類傳感器可以測量不同環境的參數,例如,周圍環境的空氣溫度和壓強、光照強度和濕度。包括如下幾個傳感器:

濕度(barometer)傳感器、光線(photometer)傳感器、溫度(thermometer)傳感器

(3)位置傳感器
這類傳感器可以測量設備的物理位置。包括如下幾個傳感器:

方向(orientation)傳感器、磁力(magnetometer)傳感器
了解后我們就開始進入傳感器的編程工作了,接下來我們看一下Android為我們提供的傳感器框架(Android sensor framework,簡稱ASF)。
2.Android傳感器框架
Android SDK為我們提供了ASF,可以用來訪問當前Android設備內置的傳感器。ASF提供了很多類和接口,幫助我們完成各種與傳感器有關的任務。例如:

1)確定當前Android設備內置了哪些傳感器。
2)確定某一個傳感器的技術指標。
3)獲取傳感器傳回來的數據,以及定義傳感器回傳數據的精度。
4)注冊和注銷傳感器事件監聽器,這些監聽器用于監聽傳感器的變化,通常從傳感器回傳的數據需要利用這些監聽器完成。
ASF允許我們訪問很多傳感器類型,這些傳感器有一些是基于硬件的傳感器,還有一些是基于軟件的傳感器。基于硬件的傳感器就是直接以芯片形式嵌入到Android設備中,這些傳感器直接從外部環境獲取數據。基于軟件的傳感器并不是實際的硬件芯片,基于軟件的傳感器傳回的數據本質上也來自于基于硬件的傳感器,只是這些數據通常會經過二次加工。所以基于軟件的傳感器也可以稱為虛擬(virtual)傳感器或合成(synthetic)傳感器。

Android對每個設備的傳感器都進行了抽象,其中SensorManger類用來控制傳感器,Sensor用來描述具體的傳感器,SensorEventListener用來監聽傳感器值的改變。
(1)SensorManager類
用于創建sensor service的實例。該類提供了很多用于訪問和枚舉傳感器,注冊和注銷傳感器監聽器的方法。而且還提供了與傳感器精度、掃描頻率、校正有關的常量。
(2)Sensor類
Sensor類為我們提供了一些用于獲取傳感器技術參數的方法。如版本、類型、生產商等。例如所有傳感器的TYPE類型如下:
注意:1-8是硬件傳感器,9是軟件傳感器,其中方向傳感器的數據來自重力和磁場傳感器,10-12是硬件或軟件傳感器。
序號|傳感器|Sensor類中定義的TYPE常量
|:-- :|:--:| :-----:| :--:|
啊|as|as

序號 傳感器 Sensor類中定義的TYPE常量
1 加速度傳感器 TYPE_ACCELEROMETER
2 溫度傳感器 TYPE_AMBIENT_TEMPERATURE
3 陀螺儀傳感器 TYPE_GYROSCOPE
4 光線傳感器 TYPE_LIGHT
5 磁場傳感器 TYPE_MAGNETIC_FIELD
6 壓力傳感器 TYPE_PRESSURE
7 臨近傳感器 TYPE_PROXIMITY
8 濕度傳感器 TYPE_RELATIVE_HUMIDITY
9 方向傳感器 TYPE_ORIENTATION
10 重力傳感器 TYPE_GRAVITY
11 線性加速傳感器 TYPE_LINEAR_ACCELERATION
12 旋轉向量傳感器 TYPE_ROTATION_VECTOR

(3)SensorEvent類
系統使用該類創建傳感器事件對象。該對象可以提供與傳感器事件有關的信息。傳感器事件對象包括的信息有原始的傳感器回傳數據、傳感器類型、數據的精度以及觸發事件的時間。
(4)SensorEventListener接口
該接口包含兩個回調方法,當傳感器的回傳值或精度發生變化時,系統會調用這兩個回調方法。

/**
 * 傳感器精度變化時回調
 */
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
/**
 * 傳感器數據變化時回調
 */
@Override
public void onSensorChanged(SensorEvent event) {
}

到了這里,我們就可以進行傳感器開發工作了。
3.獲取傳感器技術參數
下來我們編寫代碼來獲取一下自己手機的傳感器技術參數。

TextView tvSensors = (TextView) findViewById(R.id.tv_sensors);
//獲取傳感器SensorManager對象
SensorManager sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
for (Sensor sensor : sensors) {
  tvSensors.append(sensor.getName() + "\n");
}

先運行一下看看效果:
[圖片上傳失敗...(image-a87622-1567500246575)]
貌似我的手機傳感器還不少,哈哈。注意此處必須用實體機測試哦。

下來我們分別看一下動作傳感器、環境傳感器和位置傳感器的組成及使用方法。
4.動作傳感器的組成及使用方法
所有的動作傳感器都會返回三個浮點數的值(通過長度為3的數組返回),但對于不同的傳感器,這三個只是意義不同。例如,對于加速傳感器,會返回三個坐標軸的數據。對于陀螺儀傳感器,會返回三個坐標軸的旋轉角速度。

注意:動作傳感器本身一般并不會用于監測設備的位置,關于設備的位置需要用其他類型的傳感器進行監測,例如,磁場傳感器。
(1)加速度傳感器
加速度傳感器需要結合重力傳感器使用,以減少加速度受重力的影響。首先需要實現SensorEventListener接口,添加回調方法,然后獲取傳感器SensorManager對象,注冊傳感器,然后我們就可以監聽傳感器的變化了。示例代碼如下:

public class SensorActivity extends AppCompatActivity implements SensorEventListener {
  private TextView tvAccelerometer;
  private SensorManager mSensorManager;
  private float[] gravity = new float[3];
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_sensor);
    tvAccelerometer = (TextView) findViewById(R.id.tv_accelerometer);
    //獲取傳感器SensorManager對象
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  }
  /**
   * 傳感器精度變化時回調
   */
  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
  }
  /**
   * 傳感器數據變化時回調
   */
  @Override
  public void onSensorChanged(SensorEvent event) {
    //判斷傳感器類別
    switch (event.sensor.getType()) {
      case Sensor.TYPE_ACCELEROMETER: //加速度傳感器
        final float alpha = (float) 0.8;
        gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
        gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
        gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
 
        String accelerometer = "加速度傳感器\n" + "x:"
            + (event.values[0] - gravity[0]) + "\n" + "y:"
            + (event.values[1] - gravity[1]) + "\n" + "z:"
            + (event.values[2] - gravity[2]);
        tvAccelerometer.setText(accelerometer);
        //重力加速度9.81m/s^2,只受到重力作用的情況下,自由下落的加速度
        break;
      case Sensor.TYPE_GRAVITY://重力傳感器
        gravity[0] = event.values[0];//單位m/s^2
        gravity[1] = event.values[1];
        gravity[2] = event.values[2];
        break;
      default:
        break;
    }
  }
  /**
   * 界面獲取焦點,按鈕可以點擊時回調
   */
  protected void onResume() {
    super.onResume();
    //注冊加速度傳感器
    mSensorManager.registerListener(this,
        mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),//傳感器TYPE類型
        SensorManager.SENSOR_DELAY_UI);//采集頻率
    //注冊重力傳感器
    mSensorManager.registerListener(this,
        mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY),
        SensorManager.SENSOR_DELAY_FASTEST);
  }
  /**
   * 暫停Activity,界面獲取焦點,按鈕可以點擊時回調
   */
  @Override
  protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(this);
  }
 
}

我們將手機水平正面朝上放置于桌子上,看一下效果圖:
[圖片上傳失敗...(image-9ac78f-1567500246575)]
我們可以看到正值和負值,那什么情況是正值?什么情況是負值呢?

設備沿x軸正方向推動,x軸加速度為正值。
設備沿y軸正方向推動,y軸加速度為正值。
如果沿z軸正方向推動,此時手機相對于桌子水平正面朝上放置,z軸加速度為正值。由底部朝著頂部以a m/s^2的加速度推動,那么z軸的加速度為a + 9.81,所以如果計算實際的加速度(抵消重力加速度),需要減9.81。

5.位置傳感器的組成及使用方法
Android提供了磁場傳感器和方向傳感器用于確定設備的位置,還提供了測量設備正面到某一個鄰近物體距離的傳感器(鄰近傳感器)。

鄰近傳感器在手機中很常見。像接聽電話時手機屏幕滅屏就是使用的鄰近傳感器。方向傳感器是基于軟件的,該傳感器的回傳數據來自加速度傳感器和磁場傳感器。

位置傳感器對于確定設備在真實世界中的物理位置非常有用。例如,可以組合磁場傳感器和加速度傳感器測量設備相對于地磁北極的位置,還可以利用方向傳感器確定當前設備相對于自身參照系的位置。

磁場傳感器和方向傳感器都返回值3個值(SensorEvent.values),而鄰近傳感器只返回1個值。

下面我們具體看一下他們的返回值:
方向傳感器:

  • SensorEvent.values[0]:繞著Z軸旋轉的角度。如果Y軸(正常拿手機的方向)正對著北方,該值是0,如果Y軸指向南方,改值是180,Y軸指向東方,該值是90,如果Y軸指向西方,該值是270。
  • SensorEvent.values[1]:繞著X軸旋轉的度數。當從Z軸正方向朝向Y軸正方向,改值為正值。反之,為負值。該值在180至-180之間變動。
  • SensorEvent.values[2]:繞著Y軸旋轉的度數。當從Z軸正方向朝向X軸正方向,改值為正值。反之,為負值。該值在180至-180之間變動。
    磁場傳感器:
  • SensorEvent.values[0]:沿著X軸的磁力(μT,millitesla)
  • SensorEvent.values[1]:沿著Y軸的磁力(μT,millitesla)
  • SensorEvent.values[2]:沿著Y軸的磁力(μT,millitesla)
    鄰近傳感器:
    SensorEvent.values[0]:手機正面距離鄰近物理的距離(CM)
    (1)臨近傳感器
    這里以臨近傳感器作為示例工程實現一下,其他傳感器實現大同小異。
public class SensorActivity extends AppCompatActivity implements SensorEventListener {
  private TextView tvProximity;
  private SensorManager mSensorManager;
  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_motion_sensor);
    tvProximity = (TextView) findViewById(R.id.tv_proximity);
    //獲取傳感器SensorManager對象
    mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
  }
  /**
   * 傳感器精度變化時回調
   */
  @Override
  public void onAccuracyChanged(Sensor sensor, int accuracy) {
  }
  /**
   * 傳感器數據變化時回調
   */
  @Override
  public void onSensorChanged(SensorEvent event) {
    //判斷傳感器類別
    switch (event.sensor.getType()) {
      case Sensor.TYPE_PROXIMITY://臨近傳感器
        tvProximity.setText(String.valueOf(event.values[0]));
        break;
      default:
        break;
    }
  }
  /**
   * 界面獲取焦點,按鈕可以點擊時回調
   */
  protected void onResume() {
    super.onResume();
    //注冊臨近傳感器
    mSensorManager.registerListener(this,
        mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY),
        SensorManager.SENSOR_DELAY_UI);
  }
  /**
   * 暫停Activity,界面獲取焦點,按鈕可以點擊時回調
   */
  @Override
  protected void onPause() {
    super.onPause();
    mSensorManager.unregisterListener(this);
  }
 
}

運行程序,我間斷的擋住臨近傳感器,看一下效果圖:
[圖片上傳失敗...(image-d6c0ff-1567500246575)]
0.0是我擋住臨近傳感器時候的值,8.0是我將手移開時的值。

下面我們再來看一個比較叼的傳感器,與自然息息相關。
6.環境傳感器的組成及使用方法
Android提供了用于檢測不同的外部環境的傳感器。例如,可以檢測周圍空氣的濕度、光線、空氣的壓強和溫度,這些傳感器都是基于硬件的傳感器。除了光線傳感器外,其他傳感器在普通的Android設備中很少見。所以如果使用環境傳感器,最好運行時對當前Android設備所支持的傳感器進行檢測。

(1)環境傳感器的返回值

大多數動作傳感器和位置傳感器都返回多個值,而所有的環境傳感器都只返回一個值:

傳感器 Type值 返回值 單位
溫度傳感器 TYPE_AMBIENT_TEMPERATURE event.values[0] °C
壓力傳感器 TYPE_PRESSURE event.values[0] hPa
光線傳感器 TYPE_LIGHT event.values[0] lx
濕度傳感器 TYPE_RELATIVE_HUMIDITY event.values[0] RH(%)

注意:環境傳感器返回的值很少受到雜音的干擾,而動作和位置傳感器經常需要消除雜音的影響。例如,加速度傳感器要消除重力對其回傳值的影響。
(2)光線傳感器回傳數據

//最強的光線強度(估計只有沙漠地帶才能達到這個值)
public static final float LIGHT_SUNLIGHT_MAX = 120000.0f;
//萬里無云時陽光直射的強度
public static final float LIGHT_SUNLIGHT = 110000.0f;
//有陽光,但被云彩抵消了部分光線時的強度
public static final float LIGHT_SHADE = 20000.0f;
//多云時的光線強度  
public static final float LIGHT_OVERCAST = 10000.0f;
//太陽剛剛升起時(日出)的光線強度
public static final float LIGHT_SUNRISE = 400.0f;
//在陰雨天,沒有太陽時的光線強度
public static final float LIGHT_CLOUDY = 100.0f;
//夜晚有月亮時的光線強度
public static final float LIGHT_FULLMOON = 0.25f;
//夜晚沒有月亮時的光線強度(當然,也不能有路燈,就是漆黑一片)
public static final float LIGHT_NO_MOON = 0.001f;

環境傳感器的使用方法與動作、位置傳感器大同小異,在次不再贅述。
相信通過本篇文章的學習,大家都會有所提高。碼字不易,喜歡點贊

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • Android傳感器定義 Android 傳感器相關術語微機電傳感器(MEMS)MEMS 通常制作在規格很小的硅芯...
    Jannonx閱讀 4,418評論 0 1
  • 作者ivm 參考文章:http://blog.csdn.net/wenzhi20102321/article/de...
    lovesosoi閱讀 1,424評論 0 8
  • Android 傳感器開發詳解 傳感器 傳感器的分類 方向傳感器 陀螺儀傳感器 磁場傳感器 重力傳感器 線性加速度...
    CarlosLynn閱讀 4,571評論 2 2
  • Android系統提供了對傳感器的支持,如果手機設備的硬件提供了這些傳感器,Android應用可以通過傳感器來獲取...
    trampcr閱讀 4,398評論 3 12
  • 我的父親是一名虔誠的佛教信徒,我也跟著玩金剛菩提有十多年了,因自己特別愛文玩,也想與更多的朋友一起分享盤玩經驗。我...
    丿丶信仰灬傲世風閱讀 435評論 0 1