詳解Android 傳感器開(kāi)發(fā) 完全解析
大家好,由于最近會(huì)有對(duì)智能硬件相關(guān)的開(kāi)發(fā)需求,所以最近這些天分享的博文也就大致掛鉤智能硬件了,像上一篇的藍(lán)牙分享,相信很多讀者已經(jīng)看過(guò)了,那么今天我為大家?guī)?lái)Android傳感器方面知識(shí)的介紹與使用方法,對(duì)于傳感器的使用,不同版本的Android手機(jī)也許存在較大的硬件差異,但是萬(wàn)變不離其宗,本篇將通過(guò)幾個(gè)最常見(jiàn)的傳感器,滲透式的教會(huì)大家如何使用這些傳感器,帶領(lǐng)大家完成這部分的進(jìn)階提高。讓每一位Android開(kāi)發(fā)者都對(duì)傳感器的使用變得游刃有余。
1.Android的三大類傳感器
Android傳感器按大方向劃分大致有這么三類傳感器:動(dòng)作(Motion)傳感器、環(huán)境(Environmental)傳感器、位置(Position)傳感器。
(1)動(dòng)作傳感器
這類傳感器在三個(gè)軸(x、y、z)上測(cè)量加速度和旋轉(zhuǎn)角度。包括如下幾個(gè)傳感器:
加速(accelerometer)傳感器、重力(gravity)傳感器、陀螺儀(gyroscope)傳感器、旋轉(zhuǎn)向量(rotational vector )傳感器
下面來(lái)看一下傳感器世界的坐標(biāo)系:
傳感器世界的坐標(biāo)系
是不是已經(jīng)有點(diǎn)感覺(jué)了。
(2)環(huán)境傳感器
這類傳感器可以測(cè)量不同環(huán)境的參數(shù),例如,周圍環(huán)境的空氣溫度和壓強(qiáng)、光照強(qiáng)度和濕度。包括如下幾個(gè)傳感器:
濕度(barometer)傳感器、光線(photometer)傳感器、溫度(thermometer)傳感器
(3)位置傳感器
這類傳感器可以測(cè)量設(shè)備的物理位置。包括如下幾個(gè)傳感器:
方向(orientation)傳感器、磁力(magnetometer)傳感器
了解后我們就開(kāi)始進(jìn)入傳感器的編程工作了,接下來(lái)我們看一下Android為我們提供的傳感器框架(Android sensor framework,簡(jiǎn)稱ASF)。
2.Android傳感器框架
Android SDK為我們提供了ASF,可以用來(lái)訪問(wèn)當(dāng)前Android設(shè)備內(nèi)置的傳感器。ASF提供了很多類和接口,幫助我們完成各種與傳感器有關(guān)的任務(wù)。例如:
1)確定當(dāng)前Android設(shè)備內(nèi)置了哪些傳感器。
2)確定某一個(gè)傳感器的技術(shù)指標(biāo)。
3)獲取傳感器傳回來(lái)的數(shù)據(jù),以及定義傳感器回傳數(shù)據(jù)的精度。
4)注冊(cè)和注銷傳感器事件監(jiān)聽(tīng)器,這些監(jiān)聽(tīng)器用于監(jiān)聽(tīng)傳感器的變化,通常從傳感器回傳的數(shù)據(jù)需要利用這些監(jiān)聽(tīng)器完成。
ASF允許我們?cè)L問(wèn)很多傳感器類型,這些傳感器有一些是基于硬件的傳感器,還有一些是基于軟件的傳感器?;谟布膫鞲衅骶褪侵苯右孕酒问角度氲紸ndroid設(shè)備中,這些傳感器直接從外部環(huán)境獲取數(shù)據(jù)?;谲浖膫鞲衅鞑⒉皇菍?shí)際的硬件芯片,基于軟件的傳感器傳回的數(shù)據(jù)本質(zhì)上也來(lái)自于基于硬件的傳感器,只是這些數(shù)據(jù)通常會(huì)經(jīng)過(guò)二次加工。所以基于軟件的傳感器也可以稱為虛擬(virtual)傳感器或合成(synthetic)傳感器。
Android對(duì)每個(gè)設(shè)備的傳感器都進(jìn)行了抽象,其中SensorManger類用來(lái)控制傳感器,Sensor用來(lái)描述具體的傳感器,SensorEventListener用來(lái)監(jiān)聽(tīng)傳感器值的改變。
(1)SensorManager類
用于創(chuàng)建sensor service的實(shí)例。該類提供了很多用于訪問(wèn)和枚舉傳感器,注冊(cè)和注銷傳感器監(jiān)聽(tīng)器的方法。而且還提供了與傳感器精度、掃描頻率、校正有關(guān)的常量。
(2)Sensor類
Sensor類為我們提供了一些用于獲取傳感器技術(shù)參數(shù)的方法。如版本、類型、生產(chǎn)商等。例如所有傳感器的TYPE類型如下:
注意:1-8是硬件傳感器,9是軟件傳感器,其中方向傳感器的數(shù)據(jù)來(lái)自重力和磁場(chǎng)傳感器,10-12是硬件或軟件傳感器。
序號(hào) | 傳感器 | Sensor類中定義的TYPE常量 |
---|---|---|
1 | 加速度傳感器 | TYPE_ACCELEROMETER |
2 | 溫度傳感器 | TYPE_AMBIENT_TEMPERATURE |
3 | 陀螺儀傳感器 | TYPE_GYROSCOPE |
4 | 光線傳感器 | 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 | 線性加速傳感器 | TYPE_LINEAR_ACCELERATION |
12 | 旋轉(zhuǎn)向量傳感器 | TYPE_ROTATION_VECTOR |
(3)SensorEvent類
系統(tǒng)使用該類創(chuàng)建傳感器事件對(duì)象。該對(duì)象可以提供與傳感器事件有關(guān)的信息。傳感器事件對(duì)象包括的信息有原始的傳感器回傳數(shù)據(jù)、傳感器類型、數(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) { }
到了這里,我們就可以進(jìn)行傳感器開(kāi)發(fā)工作了。
3.獲取傳感器技術(shù)參數(shù)
下來(lái)我們編寫(xiě)代碼來(lái)獲取一下自己手機(jī)的傳感器技術(shù)參數(shù)。
TextView tvSensors = (TextView) findViewById(R.id.tv_sensors); //獲取傳感器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"); }
先運(yùn)行一下看看效果:
貌似我的手機(jī)傳感器還不少,哈哈。注意此處必須用實(shí)體機(jī)測(cè)試哦。
下來(lái)我們分別看一下動(dòng)作傳感器、環(huán)境傳感器和位置傳感器的組成及使用方法。
4.動(dòng)作傳感器的組成及使用方法
所有的動(dòng)作傳感器都會(huì)返回三個(gè)浮點(diǎn)數(shù)的值(通過(guò)長(zhǎng)度為3的數(shù)組返回),但對(duì)于不同的傳感器,這三個(gè)只是意義不同。例如,對(duì)于加速傳感器,會(huì)返回三個(gè)坐標(biāo)軸的數(shù)據(jù)。對(duì)于陀螺儀傳感器,會(huì)返回三個(gè)坐標(biāo)軸的旋轉(zhuǎn)角速度。
注意:動(dòng)作傳感器本身一般并不會(huì)用于監(jiān)測(cè)設(shè)備的位置,關(guān)于設(shè)備的位置需要用其他類型的傳感器進(jìn)行監(jiān)測(cè),例如,磁場(chǎng)傳感器。
(1)加速度傳感器
加速度傳感器需要結(jié)合重力傳感器使用,以減少加速度受重力的影響。首先需要實(shí)現(xiàn)SensorEventListener接口,添加回調(diào)方法,然后獲取傳感器SensorManager對(duì)象,注冊(cè)傳感器,然后我們就可以監(jiān)聽(tīng)傳感器的變化了。示例代碼如下:
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對(duì)象 mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); } /** * 傳感器精度變化時(shí)回調(diào) */ @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } /** * 傳感器數(shù)據(jù)變化時(shí)回調(diào) */ @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; } } /** * 界面獲取焦點(diǎn),按鈕可以點(diǎn)擊時(shí)回調(diào) */ protected void onResume() { super.onResume(); //注冊(cè)加速度傳感器 mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),//傳感器TYPE類型 SensorManager.SENSOR_DELAY_UI);//采集頻率 //注冊(cè)重力傳感器 mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY), SensorManager.SENSOR_DELAY_FASTEST); } /** * 暫停Activity,界面獲取焦點(diǎn),按鈕可以點(diǎn)擊時(shí)回調(diào) */ @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(this); } }
我們將手機(jī)水平正面朝上放置于桌子上,看一下效果圖:
我們可以看到正值和負(fù)值,那什么情況是正值?什么情況是負(fù)值呢?
設(shè)備沿x軸正方向推動(dòng),x軸加速度為正值。
設(shè)備沿y軸正方向推動(dòng),y軸加速度為正值。
如果沿z軸正方向推動(dòng),此時(shí)手機(jī)相對(duì)于桌子水平正面朝上放置,z軸加速度為正值。由底部朝著頂部以a m/s^2的加速度推動(dòng),那么z軸的加速度為a + 9.81,所以如果計(jì)算實(shí)際的加速度(抵消重力加速度),需要減9.81。
5.位置傳感器的組成及使用方法
Android提供了磁場(chǎng)傳感器和方向傳感器用于確定設(shè)備的位置,還提供了測(cè)量設(shè)備正面到某一個(gè)鄰近物體距離的傳感器(鄰近傳感器)。
鄰近傳感器在手機(jī)中很常見(jiàn)。像接聽(tīng)電話時(shí)手機(jī)屏幕滅屏就是使用的鄰近傳感器。方向傳感器是基于軟件的,該傳感器的回傳數(shù)據(jù)來(lái)自加速度傳感器和磁場(chǎng)傳感器。
位置傳感器對(duì)于確定設(shè)備在真實(shí)世界中的物理位置非常有用。例如,可以組合磁場(chǎng)傳感器和加速度傳感器測(cè)量設(shè)備相對(duì)于地磁北極的位置,還可以利用方向傳感器確定當(dāng)前設(shè)備相對(duì)于自身參照系的位置。
磁場(chǎng)傳感器和方向傳感器都返回值3個(gè)值(SensorEvent.values),而鄰近傳感器只返回1個(gè)值。
下面我們具體看一下他們的返回值:
方向傳感器:
- SensorEvent.values[0]:繞著Z軸旋轉(zhuǎn)的角度。如果Y軸(正常拿手機(jī)的方向)正對(duì)著北方,該值是0,如果Y軸指向南方,改值是180,Y軸指向東方,該值是90,如果Y軸指向西方,該值是270。
- SensorEvent.values[1]:繞著X軸旋轉(zhuǎn)的度數(shù)。當(dāng)從Z軸正方向朝向Y軸正方向,改值為正值。反之,為負(fù)值。該值在180至-180之間變動(dòng)。
- SensorEvent.values[2]:繞著Y軸旋轉(zhuǎn)的度數(shù)。當(dāng)從Z軸正方向朝向X軸正方向,改值為正值。反之,為負(fù)值。該值在180至-180之間變動(dòng)。
磁場(chǎng)傳感器:
- SensorEvent.values[0]:沿著X軸的磁力(μT,millitesla)
- SensorEvent.values[1]:沿著Y軸的磁力(μT,millitesla)
- SensorEvent.values[2]:沿著Y軸的磁力(μT,millitesla)
鄰近傳感器:
SensorEvent.values[0]:手機(jī)正面距離鄰近物理的距離(CM)
(1)臨近傳感器
這里以臨近傳感器作為示例工程實(shí)現(xiàn)一下,其他傳感器實(shí)現(xiàn)大同小異。
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對(duì)象 mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE); } /** * 傳感器精度變化時(shí)回調(diào) */ @Override public void onAccuracyChanged(Sensor sensor, int accuracy) { } /** * 傳感器數(shù)據(jù)變化時(shí)回調(diào) */ @Override public void onSensorChanged(SensorEvent event) { //判斷傳感器類別 switch (event.sensor.getType()) { case Sensor.TYPE_PROXIMITY://臨近傳感器 tvProximity.setText(String.valueOf(event.values[0])); break; default: break; } } /** * 界面獲取焦點(diǎn),按鈕可以點(diǎn)擊時(shí)回調(diào) */ protected void onResume() { super.onResume(); //注冊(cè)臨近傳感器 mSensorManager.registerListener(this, mSensorManager.getDefaultSensor(Sensor.TYPE_PROXIMITY), SensorManager.SENSOR_DELAY_UI); } /** * 暫停Activity,界面獲取焦點(diǎn),按鈕可以點(diǎn)擊時(shí)回調(diào) */ @Override protected void onPause() { super.onPause(); mSensorManager.unregisterListener(this); } }
運(yùn)行程序,我間斷的擋住臨近傳感器,看一下效果圖:
0.0是我擋住臨近傳感器時(shí)候的值,8.0是我將手移開(kāi)時(shí)的值。
下面我們?cè)賮?lái)看一個(gè)比較叼的傳感器,與自然息息相關(guān)。
6.環(huán)境傳感器的組成及使用方法
Android提供了用于檢測(cè)不同的外部環(huán)境的傳感器。例如,可以檢測(cè)周圍空氣的濕度、光線、空氣的壓強(qiáng)和溫度,這些傳感器都是基于硬件的傳感器。除了光線傳感器外,其他傳感器在普通的Android設(shè)備中很少見(jiàn)。所以如果使用環(huán)境傳感器,最好運(yùn)行時(shí)對(duì)當(dāng)前Android設(shè)備所支持的傳感器進(jìn)行檢測(cè)。
(1)環(huán)境傳感器的返回值
大多數(shù)動(dòng)作傳感器和位置傳感器都返回多個(gè)值,而所有的環(huán)境傳感器都只返回一個(gè)值:
傳感器 | 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(%) |
注意:環(huán)境傳感器返回的值很少受到雜音的干擾,而動(dòng)作和位置傳感器經(jīng)常需要消除雜音的影響。例如,加速度傳感器要消除重力對(duì)其回傳值的影響。
(2)光線傳感器回傳數(shù)據(jù)
//最強(qiáng)的光線強(qiáng)度(估計(jì)只有沙漠地帶才能達(dá)到這個(gè)值) public static final float LIGHT_SUNLIGHT_MAX = 120000.0f; //萬(wàn)里無(wú)云時(shí)陽(yáng)光直射的強(qiáng)度 public static final float LIGHT_SUNLIGHT = 110000.0f; //有陽(yáng)光,但被云彩抵消了部分光線時(shí)的強(qiáng)度 public static final float LIGHT_SHADE = 20000.0f; //多云時(shí)的光線強(qiáng)度 public static final float LIGHT_OVERCAST = 10000.0f; //太陽(yáng)剛剛升起時(shí)(日出)的光線強(qiáng)度 public static final float LIGHT_SUNRISE = 400.0f; //在陰雨天,沒(méi)有太陽(yáng)時(shí)的光線強(qiáng)度 public static final float LIGHT_CLOUDY = 100.0f; //夜晚有月亮?xí)r的光線強(qiáng)度 public static final float LIGHT_FULLMOON = 0.25f; //夜晚沒(méi)有月亮?xí)r的光線強(qiáng)度(當(dāng)然,也不能有路燈,就是漆黑一片) public static final float LIGHT_NO_MOON = 0.001f;
環(huán)境傳感器的使用方法與動(dòng)作、位置傳感器大同小異,在次不再贅述。
相信通過(guò)本篇的學(xué)習(xí),大家的開(kāi)發(fā)水準(zhǔn)都會(huì)有一定的提高,而大家的提高是我最欣慰的事情了。也希望大家多多支持腳本之家。
- Android編程基于距離傳感器控制手機(jī)屏幕熄滅的方法詳解
- Android利用方向傳感器獲得手機(jī)的相對(duì)角度實(shí)例說(shuō)明
- android 傳感器(OnSensorChanged)使用介紹
- Android 利用方向傳感器實(shí)現(xiàn)指南針具體步驟
- Android利用Sensor(傳感器)實(shí)現(xiàn)指南針小功能
- Android編程實(shí)現(xiàn)獲取所有傳感器數(shù)據(jù)的方法
- Android開(kāi)發(fā)中的重力傳感器用法實(shí)例詳解
- Android開(kāi)發(fā)中方向傳感器定義與用法詳解【附指南針實(shí)現(xiàn)方法】
- Android實(shí)現(xiàn)計(jì)步傳感器功能
- android實(shí)現(xiàn)手機(jī)傳感器調(diào)用
相關(guān)文章
快速解決進(jìn)入fragment時(shí)不能彈出軟件盤的問(wèn)題
下面小編就為大家?guī)?lái)一篇快速解決進(jìn)入fragment時(shí)不能彈出軟件盤的問(wèn)題。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04Android開(kāi)發(fā)Jetpack組件Lifecycle原理篇
這一篇文章來(lái)介紹Android?Jetpack架構(gòu)組件的Lifecycle;?Lifecycle用于幫助開(kāi)發(fā)者管理Activity和Fragment?的生命周期,?由于Lifecycle是LiveData和ViewModel的基礎(chǔ);所以需要先學(xué)習(xí)它2022-08-08輕松實(shí)現(xiàn)功能強(qiáng)大的Android刮獎(jiǎng)效果控件(ScratchView)
這篇文章主要為大家詳細(xì)介紹了ScratchView如何一步步打造萬(wàn)能的Android刮獎(jiǎng)效果控件,,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09android.enableD8.desugaring?=?false引發(fā)問(wèn)題解決
這篇文章主要為大家介紹了android.enableD8.desugaring?=?false引發(fā)問(wèn)題解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-03-03Android自定義View實(shí)現(xiàn)環(huán)形進(jìn)度條的思路與實(shí)例
最近看到豆瓣FM的音樂(lè)播放界面,有一個(gè)環(huán)形的進(jìn)度條挺不錯(cuò)的,最近有空就想著實(shí)現(xiàn)了,所以下面這篇文章主要給大家介紹了Android自定義View實(shí)現(xiàn)環(huán)形進(jìn)度條的思路與實(shí)例,需要的朋友可以參考借鑒,下面來(lái)一起看看吧。2017-04-04Android Studio用genymotion運(yùn)行后小圖標(biāo)無(wú)法顯示問(wèn)題
這篇文章主要介紹了Android Studio用genymotion運(yùn)行后小圖標(biāo)無(wú)法顯示的問(wèn)題,本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-04-04Flutter質(zhì)感設(shè)計(jì)之底部導(dǎo)航
這篇文章主要為大家詳細(xì)介紹了Flutter質(zhì)感設(shè)計(jì)之底部導(dǎo)航的相關(guān)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08