個月底拿到的手機HTC Nexus One,最初是在純粹的在玩的爽,後來到中關村圖書大廈看了一下午的書,最後買了兩本Android的書,然後看了看。只是看了看純基礎,也就是基礎的佈局和Activity的生命週期。
上週成都和京滬兩頭跑,什麼都沒看,這兩天又在想火車票的事情。。。。。暈啊。。。剛剛拿到票。。。長出一口氣。
關於手機重力感應的。
手機的感應器在Android裏邊所代表的類是Sensor,你只要看到在android.hardware這個包下邊的都是封裝的關於一些特殊的硬件方
面的類,比如說Camera、Sensor之類的。。一直都很懷疑爲什麼HTC的Google手機沒有前置攝像頭。。。怨念啊。。。
PS:雖然是2.1的機子,但是我用的是1.5的SDK。
在JavaEye上邊有一個很簡單的帖子,最最基礎的。
這裏:Android重力感應Demo
我自己最開始看的很多代碼都是根據這個開始改的。。。謝謝sunnyday55555
了!
代碼很簡單:我們首先要得到一個手機上的傳感器。
- SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
這行代碼只要用過類似開發的都應該知道是什麼。
getSystemService(String name)可以用來返回一個硬件設備的控制器。比如說LocationManage(和GPS相關用來確定位置的)、 TelephonyManage(查詢電話相關內容,比如說IMEI碼)、AudioManager(顧名思義,是視頻播放用的)等等。。。具體可以觀看SDK文檔裏邊 Activity的講解。在線文檔在這裏(偶爾需要翻牆)
得到重力感應的硬件控制了,然後我們就應該得到一個Sensor了。
- Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ALL);
Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ALL);
關於這個參數。。。其實挺複雜的。。。。我開始用的是TYPE_ALL,出的是XYZ三條軸線的偏移量,至於其他的大家可以看下邊:
下邊是官方SDK中對於各種類型的解析(粗體紅字是我加上去的 )
<!-- =========== ENUM CONSTANT SUMMARY =========== -->
Constants | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
int | TYPE_ACCELEROMETER | A constant describing an accelerometer sensor type.加速度 | |||||||||
int | TYPE_ALL | A constant describing all sensor types.所有類型,NexusOne默認爲 加速度 | |||||||||
int | TYPE_GYROSCOPE | A constant describing a gyroscope sensor type迴轉儀(這個不太懂) | |||||||||
int | TYPE_LIGHT | A constant describing an light sensor type.光線感應嗎 | |||||||||
int | TYPE_MAGNETIC_FIELD | A constant describing a magnetic field sensor type.磁場 | |||||||||
int | TYPE_ORIENTATION | A constant describing an orientation sensor type.定向(指北針)和角度 | |||||||||
int | TYPE_PRESSURE | A constant describing a pressure sensor type壓力計 | |||||||||
int | TYPE_PROXIMITY | A constant describing an proximity sensor type.距離?不太懂 | |||||||||
int | TYPE_TEMPERATURE | A constant describing a temperature sensor type溫度啦 |
然後就是我們需要即時瞭解手機的偏轉度。以TYPE_ALL爲例子。(其實就是TYPE_ACCELEROMETER)
PS:有時候你的機子並不會擁有這麼全的感應裝置,這個時候你應該再進行以下判斷。比如說:
- Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
- if (sensor == null ){
- log.w("NO_SERVICE" , "沒有感應溫度的感應裝置。" )
- ... ...
- }else {
- ... ...
- }
Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_TEMPERATURE);
if(sensor == null){
log.w("NO_SERVICE","沒有感應溫度的感應裝置。")
... ...
}else{
... ...
}
所有最基本的三維座標系有三個軸:X、Y和Z,這個學過矩陣或者線性代數的都應該知道吧(~~~~(>_<)~~~~ 我當年線性代數掛了。。。。慘不忍睹啊。。。後來自學DirectX的時候才覺得原來矩陣變換是這麼的重要。。而且更重要的是這個一點也不難嗎。。。。 )
關於手機的XYZ座標,把你的手機平放到桌子上,橫x,縱y,然後z就是屏幕法線。
官方的例子:(直接粘貼的話空格會變小,所以就截圖了 )
然後我們註冊一個Listener,用來監聽我們所得到的值的改變。
- SensorEventListener lsn = new SensorEventListener() {
- public void onSensorChanged(SensorEvent e) {
- x = e.values[SensorManager.DATA_X];
- y = e.values[SensorManager.DATA_Y];
- z = e.values[SensorManager.DATA_Z];
- t.setText("x=" + Math.round(x * ROUND_NUMBER) + "," + "y="
- + Math.round(y * ROUND_NUMBER) + "," + "z="
- + Math.round(z * ROUND_NUMBER));
- }
- public void onAccuracyChanged(Sensor s, int accuracy) {
- }
- };
SensorEventListener lsn = new SensorEventListener() {
public void onSensorChanged(SensorEvent e) {
x = e.values[SensorManager.DATA_X];
y = e.values[SensorManager.DATA_Y];
z = e.values[SensorManager.DATA_Z];
t.setText("x=" + Math.round(x * ROUND_NUMBER) + "," + "y="
+ Math.round(y * ROUND_NUMBER) + "," + "z="
+ Math.round(z * ROUND_NUMBER));
}
public void onAccuracyChanged(Sensor s, int accuracy) {
}
};
在這裏我把數字放大了,我預先定義了一個變量ROUND_NUMBER ,是爲了以後用來更改靈敏度的。我取的值是100。
這個就簡單了,我們首先聲明一個SensorEvent的監聽,每當它得到的值改變的時候,我就在一個TextView t 上邊輸出改變了的值。
在這裏使用TYPE_ALL返回的值SensorEvent裏邊的values就是得到的數字。
得到的values默認是一個float[] 。也就是說是一個float類型的數組。他在TYPE_ALL的聲明下一共返回三個值,分別就是x、y、z軸的值,假如你將手機平放在水平面上,默認分別是0,0,10。(我在網上查到有的人和我得到的數字不一樣,有人說是0,0,-10,關於這個我不知道是爲什麼,如果有人的Gphone比較多的話可以看看是怎麼一回事 ),而當你將手機垂直立起,顯示的應當是0,10,0。
PS: SensorManager裏邊有很多的有意思的常量,比如說SensorManager.GRAVITY_EARTH 是地球的重力加速度,當然也有GRAVITY_MARS 火星的,GRAVITY_MOON 月球的,最惡搞的還有GRAVITY_DEATH_STAR_I (星球大戰裏的衛星武器死星I號)。。。。還有一個GRAVITY_THE_ISLAND ,這個不知道是哪裏。。。汗。。。難道是《島》這本書裏的世界?還是Neverland?
然後我們可以給Manager註冊一個監聽。
- sensorMgr.registerListener(lsn, sensor,
- SensorManager.SENSOR_DELAY_GAME);
sensorMgr.registerListener(lsn, sensor,
SensorManager.SENSOR_DELAY_GAME);
三個參數分別是監聽,感應裝置,和靈敏度。
靈敏度分爲:
SENSOR_DELAY_FASTEST
最靈敏,快的然你無語
SENSOR_DELAY_GAME
遊戲的時候用這個,不過一般用這個就夠了,和上一個很難看出區別(也許是我的手機CPU高?1GHz的。。。)
SENSOR_DELAY_NORMAL
比較慢。
SENSOR_DELAY_UI
最慢的,幾乎就是橫和縱的區別
也許有些人想要拿這個來練練手了。比如說是現在每天播放的聯通iPhone廣告裏有一個“可以用來測量相框水平 ”這個廣告詞。
但是,但是。。。。恩恩。。。。輸出的最好還是角度比較好吧?
所以我們改一改,做一個基本的LevelBar。。。沒有什麼圖形界面,只是用來輸出。
我們首先註冊的Sensor應該改了。。。不是TYPE_ALL ,而是TYPE_ORIENTATION !
然後剩下的基本上都一樣。SensorEvent 返回的values也是三個值的數組。但是 ,這三個值還是稍微有些不同的,如果你看了輸出的值,那麼就可能會明白了。
首先是第一個,有些人發現就算是平放在桌面上第一個值也會變,那麼,第一個值其實不是軸角度,而是方向。
對了,這就是我在隨上邊寫的指北針 !當數字是0 的時候,你的手機指向的是正北 方向,90的話是東 ,180是南 ,270是西 。這下子,再加上一個漂亮的圖形界面,一個指南針軟件就可以出來了吧。
然後是第二個和第三個,就是x,y軸的角度值!對,是角度值而且不用換算。這樣子,你可以把屏幕橫過來,然後直接輸出y軸的角度值了,什麼時候他是90度,那麼就是水平了!
代碼就不貼了。。。。可以看我一開始給的鏈接。sunnyday55555寫的就足夠用了
PS:關於靈敏度,不要調的太靈敏了,我放在桌子上都一直在變。。。。
PS:PS:馬上過年了,我回家是沒有網絡的,而且我美工很差,希望有哪位做一個像是蘋果iPhone的LevelBar一樣的軟件,放到market上邊免費下一下。