知識(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)傳感器。
-
動(dòng)作傳感器
下面來(lái)看一下傳感器世界的坐標(biāo)系:
這類(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 )傳感器
20180115223132900.png 環(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)] )傳感器位置傳感器
這類(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)

//創(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();
}
- 磁場(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 );
-
計(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);