傳感器

知識(shí)要點(diǎn):

1、傳感器的簡(jiǎn)介及分類(lèi)

1.1傳感器的概述及應(yīng)用場(chǎng)景
1.2傳感器分類(lèi)介紹

2、方向傳感器獲取參數(shù)的實(shí)現(xiàn)

2.1 SensorEvent類(lèi)
2.2 SensorEventListener接口
2.3 SensorManager
2.4 每種傳感器對(duì)應(yīng)的常量值

案例:微信搖一搖、指南針、計(jì)步器

目標(biāo)要求:

1、了解傳感器在開(kāi)發(fā)中的使用

2、了解傳感器開(kāi)發(fā)場(chǎng)景

3、掌握方向傳感器獲取參數(shù)

一.Android的三大類(lèi)傳感器

?Android傳感器按大方向劃分大致有三類(lèi)傳感器:動(dòng)作(Motion)傳感器、環(huán)境(Environmental)傳感器、位置(Position)傳感器。

  1. 動(dòng)作傳感器
    這類(lèi)傳感器在三個(gè)軸(x、y、z)上測(cè)量加速度和旋轉(zhuǎn)角度。包括如下幾個(gè)傳感器:加速(accelerometer [?k?sel??r?m?t?(r)])傳感器、重力(gravity)傳感器、陀螺儀(gyroscope [?d?a?r?sk??p])傳感器、旋轉(zhuǎn)向量(rotational vector )傳感器

    下面來(lái)看一下傳感器世界的坐標(biāo)系:
    20180115223132900.png
  2. 環(huán)境傳感器
    這類(lèi)傳感器可以測(cè)量不同環(huán)境的參數(shù),例如,周?chē)h(huán)境的空氣溫度和壓強(qiáng)、光照強(qiáng)度和濕度。包括如下幾個(gè)傳感器:
    濕度(barometer)傳感器、光線(xiàn)(photometer)傳感器、溫度(thermometer [θ??m?m?t?(r)] )傳感器

  3. 位置傳感器
    這類(lèi)傳感器可以測(cè)量設(shè)備的物理位置。包括如下幾個(gè)傳感器:方向(orientation)傳感器、磁力(magnetometer)傳感器

  • 了解后我們就開(kāi)始進(jìn)入傳感器的編程工作了,接下來(lái)我們看一下Android為我們提供的傳感器框架(Android sensor framework,簡(jiǎn)稱(chēng)ASF)。
    二.Android傳感器框架

?Android SDK為我們提供了ASF,可以用來(lái)訪(fǎng)問(wèn)當(dāng)前Android設(shè)備內(nèi)置的傳感器。ASF提供了很多類(lèi)和接口,幫助我們完成各種與傳感器有關(guān)的任務(wù)。例如:

1)確定當(dāng)前Android設(shè)備內(nèi)置了哪些傳感器。
2)確定某一個(gè)傳感器的技術(shù)指標(biāo)。
3)獲取傳感器傳回來(lái)的數(shù)據(jù),以及定義傳感器回傳數(shù)據(jù)的精度。
4)注冊(cè)和注銷(xiāo)傳感器事件監(jiān)聽(tīng)器,這些監(jiān)聽(tīng)器用于監(jiān)聽(tīng)傳感器的變化,通常從傳感器回傳的數(shù)據(jù)需要利用這些監(jiān)聽(tīng)器完成。

ASF允許我們?cè)L問(wèn)很多傳感器類(lèi)型,這些傳感器有一些是基于硬件的傳感器,還有一些是基于軟件的傳感器?;谟布膫鞲衅骶褪侵苯右孕酒问角度氲紸ndroid設(shè)備中,這些傳感器直接從外部環(huán)境獲取數(shù)據(jù)。基于軟件的傳感器并不是實(shí)際的硬件芯片,基于軟件的傳感器傳回的數(shù)據(jù)本質(zhì)上也來(lái)自于基于硬件的傳感器,只是這些數(shù)據(jù)通常會(huì)經(jīng)過(guò)二次加工。所以基于軟件的傳感器也可以稱(chēng)為虛擬(virtual)傳感器或合成(synthetic)傳感器。

Android對(duì)每個(gè)設(shè)備的傳感器都進(jìn)行了抽象,其中SensorManger類(lèi)用來(lái)控制傳感器,Sensor用來(lái)描述具體的傳感器,SensorEventListener用來(lái)監(jiān)聽(tīng)傳感器值的改變。

(1)SensorManager類(lèi)

用于創(chuàng)建sensor service的實(shí)例。該類(lèi)提供了很多用于訪(fǎng)問(wèn)和枚舉傳感器,注冊(cè)和注銷(xiāo)傳感器監(jiān)聽(tīng)器的方法。而且還提供了與傳感器精度、掃描頻率、校正有關(guān)的常量。

(2)Sensor類(lèi)

Sensor類(lèi)為我們提供了一些用于獲取傳感器技術(shù)參數(shù)的方法。如版本、類(lèi)型、生產(chǎn)商等。例如所有傳感器的TYPE類(lèi)型如下:

Sensor類(lèi)為我們提供了一些用于獲取傳感器技術(shù)參數(shù)的方法。如版本、類(lèi)型、生產(chǎn)商等。例如所有傳感器的TYPE類(lèi)型如下:

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

注意:1-8是硬件傳感器,9是軟件傳感器,其中方向傳感器的數(shù)據(jù)來(lái)自重力和磁場(chǎng)傳感器,10-12是硬件或軟件傳感器。

(3)SensorEvent類(lèi)

系統(tǒng)使用該類(lèi)創(chuàng)建傳感器事件對(duì)象。該對(duì)象可以提供與傳感器事件有關(guān)的信息。傳感器事件對(duì)象包括的信息有原始的傳感器回傳數(shù)據(jù)、傳感器類(lèi)型、數(shù)據(jù)的精度以及觸發(fā)事件的時(shí)間。

(4)SensorEventListener接口

該接口包含兩個(gè)回調(diào)方法,當(dāng)傳感器的回傳值或精度發(fā)生變化時(shí),系統(tǒng)會(huì)調(diào)用這兩個(gè)回調(diào)方法。

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

三.獲取傳感器技術(shù)參數(shù)

下來(lái)我們編寫(xiě)代碼來(lái)獲取一下自己手機(jī)的傳感器技術(shù)參數(shù)。

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

各種傳感器的使用:

1.加速度傳感器

在這這之前先了解一下手機(jī)傳感器世界的三維坐標(biāo)

20180115223132900.png
//創(chuàng)建一個(gè)SensorManager來(lái)獲取系統(tǒng)的傳感器服務(wù)
sm = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
   /*
     * 最常用的一個(gè)方法 注冊(cè)事件
     * 參數(shù)1 :傳感器的監(jiān)聽(tīng)器
     * 參數(shù)2 :待監(jiān)聽(tīng)的傳感器
     * 參數(shù)3 :模式 可選數(shù)據(jù)變化的刷新頻率,多少微秒取一次。
     *        SensorManager.SENSOR_DELAY_FASTEST:最快,延遲最小。
     *        SensorManager.SENSOR_DELAY_GAME:適合游戲的頻率。
     *        SensorManager.SENSOR_DELAY_NORMAL:正常頻率。
     *        SensorManager.SENSOR_DELAY_UI:適合普通用戶(hù)界面UI變化的頻率。
     * */
//加速度傳感器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);

接下來(lái)我們只要監(jiān)聽(tīng)這個(gè)傳感器值的變化,然后更新textView的值就好了

@Override
public void onSensorChanged(SensorEvent sensorEvent) {
    if (sensorEvent.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        float X_lateral = sensorEvent.values[0];
        float Y_longitudinal = sensorEvent.values[1];
        float Z_vertical = sensorEvent.values[2];
        mtextViewx.setText(X_lateral + "");
        mtextViewy.setText(Y_longitudinal + "");
        mtextViewz.setText(Z_vertical + "");
    }
}

在activity變?yōu)椴豢梢?jiàn)的時(shí)候,傳感器依然在工作,這樣很耗電,所以我們根據(jù)需求可以在onStop方法里面停掉傳感器的工作

@Override
public void onStop() {
    sm.unregisterListener(this);
    super.onStop();
}
  1. 磁場(chǎng)傳感器

和加速度計(jì)一樣,為sensormanager監(jiān)聽(tīng)磁場(chǎng)變化即可,把手機(jī)放在電腦旁邊時(shí)候可以清楚看到數(shù)值的變化

// 為磁場(chǎng)傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD), SensorManager.SENSOR_DELAY_NORMAL);
else if(sensorEvent.sensor.getType() == Sensor.TYPE_MAGNETIC_FIELD){
    float X_lateral = sensorEvent.values[0];
    float Y_longitudinal = sensorEvent.values[1];
    float Z_vertical = sensorEvent.values[2];
    mtextView1.setText("x軸的磁場(chǎng)強(qiáng)度\n"+ X_lateral );
    mtextView2.setText("y軸的磁場(chǎng)強(qiáng)度\n"+ Y_longitudinal );
    mtextView3.setText("z軸的磁場(chǎng)強(qiáng)度\n"+ Z_vertical );
}

3.方向傳感器

這個(gè)可以用來(lái)做指南針之類(lèi)的,繞z軸轉(zhuǎn)過(guò)的角度為0時(shí)大概指向正北。這個(gè)TYPE_ORIENTATION接口不夠精確已經(jīng)過(guò)時(shí)了,可以使用旋轉(zhuǎn)矩陣來(lái)代替。這里繞z軸轉(zhuǎn)過(guò)的角度是value[0],看源碼可得

// 為方向傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ORIENTATION), SensorManager.SENSOR_DELAY_NORMAL);
else if(sensorEvent.sensor.getType() == Sensor.TYPE_ORIENTATION){
    float X_lateral = sensorEvent.values[0];
    float Y_longitudinal = sensorEvent.values[1];
    float Z_vertical = sensorEvent.values[2];
    mtextView4.setText("繞z軸轉(zhuǎn)過(guò)的角度\n"+ X_lateral );
    mtextView5.setText("繞x軸轉(zhuǎn)過(guò)的角度\n"+ Y_longitudinal );
    mtextView6.setText("繞y軸轉(zhuǎn)過(guò)的角度\n"+ Z_vertical );
}

4.陀螺儀傳感器

// 為陀螺儀傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_GYROSCOPE), SensorManager.SENSOR_DELAY_NORMAL);
else if(sensorEvent.sensor.getType() == Sensor.TYPE_GYROSCOPE){
    //需要將弧度轉(zhuǎn)為角度
    float X = (float)Math.toDegrees(sensorEvent.values[0]);
    float Y = (float)Math.toDegrees(sensorEvent.values[1]);
    float Z = (float)Math.toDegrees(sensorEvent.values[2]);
    mtextView7.setText("繞x軸轉(zhuǎn)過(guò)的角速度\n"+ X );
    mtextView8.setText("繞y軸轉(zhuǎn)過(guò)的角速度\n"+ Y );
    mtextView9.setText("繞z軸轉(zhuǎn)過(guò)的角速度\n"+ Z );
}

5.重力傳感器

就是把重力加速度分解到xyz三個(gè)方向上

// 為重力傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_GRAVITY), SensorManager.SENSOR_DELAY_NORMAL);
else if(sensorEvent.sensor.getType() == Sensor.TYPE_GRAVITY){
    float X = sensorEvent.values[0];
    float Y = sensorEvent.values[1];
    float Z = sensorEvent.values[2];
    mtextViewgx.setText("x方向的重力加速度\n"+ X );
    mtextViewgy.setText("Y方向的重力加速度\n"+ Y );
    mtextViewgz.setText("Z方向的重力加速度\n"+ Z );

6.線(xiàn)性加速度傳感器

就是去掉重力加速度后各個(gè)方向的加速度

// 為線(xiàn)性加速度傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION), SensorManager.SENSOR_DELAY_NORMAL);
else if(sensorEvent.sensor.getType() == Sensor.TYPE_LINEAR_ACCELERATION){
    float X = sensorEvent.values[0];
    float Y = sensorEvent.values[1];
    float Z = sensorEvent.values[2];
    mtextViewlx.setText("x方向的線(xiàn)性加速度\n"+ X );
    mtextViewly.setText("Y方向的線(xiàn)性加速度\n"+ Y );
    mtextViewlz.setText("Z方向的線(xiàn)性加速度\n"+ Z );
}

7.溫度傳感器

這里的TYPE_TEMPERATURE已經(jīng)過(guò)時(shí),測(cè)出來(lái)的是cpu的溫度,所以測(cè)出來(lái)的數(shù)值有點(diǎn)大,如果測(cè)環(huán)境溫度的話(huà)應(yīng)該使用

// 為溫度傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_TEMPERATURE), SensorManager.SENSOR_DELAY_NORMAL);

else if(sensorEvent.sensor.getType() == Sensor.TYPE_TEMPERATURE){
    float X = sensorEvent.values[0];
    mtextView10.setText("溫度為"+ X );
}

8.光傳感器

// 為光傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_LIGHT), SensorManager.SENSOR_DELAY_NORMAL);

else if(sensorEvent.sensor.getType() == Sensor.TYPE_LIGHT){
    float X = sensorEvent.values[0];
    mtextView11.setText("光強(qiáng)度為為"+ X );
}

9.距離傳感器

可以控制手機(jī)打電話(huà)時(shí)候息屏,如果使用光線(xiàn)傳感器的話(huà)在黑夜中打電話(huà)就自動(dòng)息屏了

// 為距離傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_PROXIMITY), SensorManager.SENSOR_DELAY_NORMAL);

else if(sensorEvent.sensor.getType() == Sensor.TYPE_PROXIMITY){
    float X = sensorEvent.values[0];
    mtextView12.setText("距離為"+ X );
}

10.壓力傳感器

// 為壓力傳感器注冊(cè)監(jiān)聽(tīng)器
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_PRESSURE), SensorManager.SENSOR_DELAY_NORMAL);

else if(sensorEvent.sensor.getType() == Sensor.TYPE_PRESSURE){
    float X = sensorEvent.values[0];
    mtextView13.setText("壓強(qiáng)為"+ X );
  1. 計(jì)步傳感器
    有兩個(gè)接口,一個(gè)Counter統(tǒng)計(jì)的是總步數(shù),而DETECTOR為該計(jì)步是否有效,有效的話(huà)就置1
// 計(jì)步統(tǒng)計(jì)
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_STEP_COUNTER), SensorManager.SENSOR_DELAY_NORMAL);
// 單次計(jì)步
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR), SensorManager.SENSOR_DELAY_NORMAL);

else if(sensorEvent.sensor.getType() == Sensor.TYPE_STEP_COUNTER){
    float X = sensorEvent.values[0];
    mtextView14.setText("COUNTER:"+ X );
} else if(sensorEvent.sensor.getType() == Sensor.TYPE_STEP_DETECTOR){
    //檢測(cè)到走動(dòng)時(shí)值為1
    float X = sensorEvent.values[0];
    mtextView15.setText("DECTOR:"+ X );
}

四.微信搖一搖

1.在onStart() 方法中獲取傳感器的SensorManager

@Override
protected void onStart() {
    super.onStart();
    //獲取 SensorManager 負(fù)責(zé)管理傳感器
    mSensorManager = ((SensorManager) getSystemService(SENSOR_SERVICE));
    if (mSensorManager != null) {
        //獲取加速度傳感器
        mAccelerometerSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        if (mAccelerometerSensor != null) {
            mSensorManager.registerListener(this, mAccelerometerSensor, SensorManager.SENSOR_DELAY_UI);
        }
    }
}

2.緊接著我們就要在Stop中注銷(xiāo)傳感器

@Override
protected void onStop() {
    // 務(wù)必要在pause中注銷(xiāo) mSensorManager
    // 否則會(huì)造成界面退出后搖一搖依舊生效的bug
    if (mSensorManager != null) {
        mSensorManager.unregisterListener(this);
    }
    super.onStop();
}

3.在step1中的注冊(cè)監(jiān)聽(tīng)事件方法中, 我們傳入了當(dāng)前Activity對(duì)象, 故讓其實(shí)現(xiàn)回調(diào)接口, 得到以下方法

@Override
public void onSensorChanged(SensorEvent event) {
    int type = event.sensor.getType();

    if (type == Sensor.TYPE_ACCELEROMETER) {
        //獲取三個(gè)方向值
        float[] values = event.values;
        float x = values[0];
        float y = values[1];
        float z = values[2];

        if ((Math.abs(x) > 17 || Math.abs(y) > 17 || Math
                .abs(z) > 17) && !isShake) {
            // TODO: 2016/10/19 實(shí)現(xiàn)搖動(dòng)邏輯, 搖動(dòng)后進(jìn)行震動(dòng)和聲音
        }
    }
}

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}

4.振動(dòng)和聲音

震動(dòng)權(quán)限:<uses-permission android:name="android.permission.VIBRATE"/>

MediaPlayer player = MediaPlayer.create(this, R.raw.weichat_audio);
player.start();

//獲取Vibrator震動(dòng)服務(wù)
mVibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
//方式1
mVibrator.vibrate(1000);//振動(dòng)一秒
//方式2
//這里使用的是一個(gè)長(zhǎng)整型數(shù)組,數(shù)組的a[0]表示靜止的時(shí)間,a[1]代表的是震動(dòng)的時(shí)間,然后數(shù)組的a[2]表示靜止的時(shí)間,a[3]代表的是震動(dòng)的時(shí)間……依次類(lèi)推下去,然后這里的代碼有一點(diǎn)小小的改變:
long[] patter = {1000, 1000, 2000, 50};
mVibrator.vibrate(patter, 0);
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容