Android重力感應(轉)

個月底拿到的手機HTC Nexus One,最初是在純粹的在玩的爽,後來到中關村圖書大廈看了一下午的書,最後買了兩本Android的書,然後看了看。只是看了看純基礎,也就是基礎的佈局和Activity的生命週期。

上週成都和京滬兩頭跑,什麼都沒看,這兩天又在想火車票的事情。。。。。暈啊。。。剛剛拿到票。。。長出一口氣。

關於手機重力感應的。

手機的感應器在Android裏邊所代表的類是Sensor,你只要看到在android.hardware這個包下邊的都是封裝的關於一些特殊的硬件方 面的類,比如說Camera、Sensor之類的。。一直都很懷疑爲什麼HTC的Google手機沒有前置攝像頭。。。怨念啊。。。

 

PS:雖然是2.1的機子,但是我用的是1.5的SDK。

在JavaEye上邊有一個很簡單的帖子,最最基礎的。
這裏:Android重力感應Demo
我自己最開始看的很多代碼都是根據這個開始改的。。。謝謝sunnyday55555 了!


代碼很簡單:我們首先要得到一個手機上的傳感器。

 

Java代碼
  1. SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);  
SensorManager sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);
 

這行代碼只要用過類似開發的都應該知道是什麼。

getSystemService(String name)可以用來返回一個硬件設備的控制器。比如說LocationManage(和GPS相關用來確定位置的)、 TelephonyManage(查詢電話相關內容,比如說IMEI碼)、AudioManager(顧名思義,是視頻播放用的)等等。。。具體可以觀看SDK文檔裏邊 Activity的講解。在線文檔在這裏(偶爾需要翻牆)

 

得到重力感應的硬件控制了,然後我們就應該得到一個Sensor了。

Java代碼
  1. 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:有時候你的機子並不會擁有這麼全的感應裝置,這個時候你應該再進行以下判斷。比如說:

Java代碼
  1. Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_TEMPERATURE);  
  2.   
  3. if (sensor ==  null ){  
  4.         log.w("NO_SERVICE" , "沒有感應溫度的感應裝置。" )  
  5.         ... ...  
  6. }else {  
  7.         ... ...  
  8. }  
Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_TEMPERATURE);

if(sensor == null){
        log.w("NO_SERVICE","沒有感應溫度的感應裝置。")
        ... ...
}else{
        ... ...
}
 

所有最基本的三維座標系有三個軸:X、Y和Z,這個學過矩陣或者線性代數的都應該知道吧(~~~~(>_<)~~~~ 我當年線性代數掛了。。。。慘不忍睹啊。。。後來自學DirectX的時候才覺得原來矩陣變換是這麼的重要。。而且更重要的是這個一點也不難嗎。。。。

 

關於手機的XYZ座標,把你的手機平放到桌子上,橫x,縱y,然後z就是屏幕法線。

 

官方的例子:(直接粘貼的話空格會變小,所以就截圖了 )

 

然後我們註冊一個Listener,用來監聽我們所得到的值的改變。

Java代碼
  1. SensorEventListener lsn =  new  SensorEventListener() {  
  2.             public   void  onSensorChanged(SensorEvent e) {  
  3.                 x = e.values[SensorManager.DATA_X];  
  4.                 y = e.values[SensorManager.DATA_Y];  
  5.                 z = e.values[SensorManager.DATA_Z];  
  6.                 t.setText("x="  + Math.round(x * ROUND_NUMBER) +  ","  +  "y="   
  7.                         + Math.round(y * ROUND_NUMBER) + ","  +  "z="   
  8.                         + Math.round(z * ROUND_NUMBER));  
  9.             }  
  10.   
  11.             public   void  onAccuracyChanged(Sensor s,  int  accuracy) {  
  12.             }  
  13.         };  
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註冊一個監聽。

Java代碼
  1. sensorMgr.registerListener(lsn, sensor,  
  2.                 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上邊免費下一下。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章