曾幾何時(shí),本人寫了一篇Android傳感器初探"驚艷整個(gè)籃球場"...一轉(zhuǎn)眼兩年過去了,真是物逝人非,技術(shù)更新的快啊,如今都已經(jīng)4.0巧克力冰激凌了...
0. 總論
本文希望分別從動(dòng)態(tài)角度(應(yīng)用程序進(jìn)程)以及靜態(tài)角度(框架體系架構(gòu))兩方面來理解傳感器系統(tǒng)。
1. 上層應(yīng)用
從編寫應(yīng)用程序的角度來看,比較簡單,大體分如下4步,便可得到一個(gè)傳感器實(shí)時(shí)上報(bào)的數(shù)值并作處理,
1) 得到傳感器服務(wù) getSystemService(SENSOR_SERVICE);
得到一個(gè)SensorManager,用來管理分配調(diào)度處理Sensor的工作,注意它并不服務(wù)運(yùn)行于后臺,真正屬于Sensor的系統(tǒng)服務(wù)是SensorService,終端下#service list可以看到sensorservice: [android.gui.SensorServer]。
2) 得到傳感器類型 getDefaultSensor(Sensor.TYPE_GRAVITY);
當(dāng)然還有各種千奇百怪的傳感器,可以查閱Android官網(wǎng)API或者源碼Sensor.java。
3) 注冊監(jiān)聽器 SensorEventListener
應(yīng)用程序打開一個(gè)監(jiān)聽接口,專門處理傳感器的數(shù)據(jù),這個(gè)監(jiān)聽機(jī)制比較重要,被系統(tǒng)廣泛使用。
4) 實(shí)現(xiàn)監(jiān)聽器的回調(diào)函數(shù) onSensorChanged, onAccuracyChanged
例如對重力感應(yīng)器的xyz值經(jīng)算法變換得到左右上下前后方向等,就由這個(gè)回調(diào)函數(shù)實(shí)現(xiàn)。
1.1 進(jìn)程空間
一個(gè)應(yīng)用程序?qū)?yīng)一個(gè)虛擬機(jī)實(shí)例,一個(gè)進(jìn)程和一個(gè)主線程,通過主線程控制四大組件。
要想得到傳感器數(shù)據(jù),須要開一個(gè)子線程,通過pol輪訓(xùn)的方式監(jiān)聽底層上報(bào)的數(shù)據(jù),再由消息機(jī)制把數(shù)據(jù)發(fā)送給主線程處理。
換句話說,應(yīng)用程序有兩個(gè)任務(wù):
1)準(zhǔn)備一個(gè)監(jiān)聽接口供主線程接受數(shù)據(jù)
2)開啟一個(gè)子線程接受底層數(shù)據(jù)并發(fā)送到主線程,
而這些有關(guān)Sensor的具體任務(wù),全部交給SensorManager統(tǒng)一管理。
1.2 Android SDK API
上層通過SDK API得到Java框架,這里,應(yīng)用程序通過AIDL接口遠(yuǎn)程調(diào)用(RPC)得到SensorManager.
可查閱官網(wǎng)SDK API android.hardware.SensorManager類提供的方法。
簡單粗暴概括地講,上層要拿底層數(shù)據(jù),無外乎兩部分,
1)設(shè)備的類型 (控制流)
getSensorList()得到傳感器類型,取得sensorList列表的過程由上至下,java框架->JNI->本地框架 ->標(biāo)準(zhǔn)抽象層->設(shè)備驅(qū)動(dòng)
2) 設(shè)備的數(shù)據(jù) (數(shù)據(jù)流)
registerListener()注冊監(jiān)聽器的時(shí)候會開啟一個(gè)線程,其中sensor_data_poll同樣由上至下最后拿到底層數(shù)據(jù)。
寫到這里,摘抄別人的一段話...
我們在學(xué)習(xí)新系統(tǒng)時(shí),首先映入眼簾的就是新概念。新名詞,就如現(xiàn)在我們面臨的Android大量的新名詞,在程序員的世界都是從代碼實(shí)踐開始的,是從寫應(yīng)用開始去涉及。SDK給了我們一個(gè)概念,我們就在這個(gè)概念框架下,使用SDK給我提供的函數(shù)接口,數(shù)據(jù)結(jié)構(gòu),初始化過程等,我們最初的接觸到原型就是“HelloWorld”之類的DEMO程序,我們在Hello world上去使用各種不同的接口函數(shù),對于應(yīng)用程序員來講,他說看到的系統(tǒng)就是系統(tǒng)調(diào)用接口,及其編程開發(fā)流程。實(shí)際上只要一使用這些接口,就不得不接受一系列的概念,只有在這種概念系統(tǒng)下,我們才能工作。但是,實(shí)際上我們卻忽略了這樣的概念系統(tǒng)的理解,只是在編程接口的這個(gè)狹窄的空間去理解系統(tǒng).我們理解系統(tǒng)在形成理解概念的空間只是微小的一角,很少有資料來介紹這種概念系統(tǒng)的形成和理解,編程接口只是這個(gè)概念空間一個(gè),對外部的一個(gè)表征。我們可以抽象起來,以接口,協(xié)議和行為,來描述系統(tǒng)的情況。SDK API的實(shí)質(zhì)向上層提供了一個(gè)語義接口,從而在層間實(shí)現(xiàn)了一個(gè)轉(zhuǎn)義過程,同時(shí)又成為一個(gè)功能的集合體。但是我們很少這樣跳出來看,我們到底是處于一種什么樣的概念空間,SDK除了調(diào)用接口外,還給了我們怎樣一種整體概念?目標(biāo)系統(tǒng)的基本構(gòu)架在本質(zhì)上的東西就是一個(gè)概念系統(tǒng)到另一個(gè)概念系統(tǒng)的映射。讓我們大腦理解的概念系統(tǒng)映射到計(jì)算機(jī)能實(shí)現(xiàn)的概念域的一個(gè)映射。我們假定這個(gè)概念域E,機(jī)器能夠理解的概念域?yàn)镸,我們的軟件工程要做的事情實(shí)質(zhì)就是:EàM領(lǐng)域的一個(gè)映射過程。
2 Java框架
上層由getSystemService(SENSOR_SERVICE);得到一個(gè)SensorManager實(shí)例,為上層提供方法。
除了上文的兩個(gè)method,SensorManager本身的構(gòu)造函數(shù)很有必要看下,
nativeClassInit(); 在JNI層得到android.hardware.Sensor的JNI環(huán)境指針env.
sensors_module_init(); 通過JNI調(diào)用本地框架,得到SensorService,SensorService初始化控制流各功能。
new Sensor(); 建立一個(gè)Sensor對象,可查閱官網(wǎng)API android.hardware.Sensor
sensors_module_get_next_sensor(); 上層得到設(shè)備支持的所有Sensor,并放入SensorList鏈表。
new SensorThread(); 創(chuàng)建Sensor線程,當(dāng)應(yīng)用程序registerListener()注冊監(jiān)聽器的時(shí)候開啟線程run(),注意當(dāng)沒有數(shù)據(jù)變化時(shí),線程會阻塞。
站在上層的角度,我們看不到SensorManager做了兩件重要的工作,即
1) 得到本地框架SensorManager.cpp,獲得Sensor真正的后臺服務(wù)SensorService
2) 創(chuàng)建EventQueue用來管理數(shù)據(jù),這個(gè)是4.0新版本的一大變化,這個(gè)變化,導(dǎo)致抽象層有關(guān)數(shù)據(jù)流的內(nèi)容全部重寫...
3 本地框架
為了不陷入茫茫的代碼海洋,這里簡單的做個(gè)總結(jié),
SensorManager負(fù)責(zé)控制流,通過C/S binder機(jī)制與SensorService通信。
SensorEventQueue負(fù)責(zé)數(shù)據(jù)流,通過管道機(jī)制讀寫底層數(shù)據(jù)。
SensorSevice把任務(wù)交給SensorDevice,SensorDevice調(diào)用標(biāo)準(zhǔn)的抽象層接口。
Sensor架構(gòu)的抽象層接口是最標(biāo)準(zhǔn)的一種,它很好的實(shí)現(xiàn)了抽象層與本地框架的分離。
當(dāng)然還有其它類型的抽象層接口,這里不作討論。