重力感应

来源:互联网 发布:udp 端口 编辑:程序博客网 时间:2024/04/27 16:36

http://www.javaeye.com/topic/592409

关于手机重力感应的。

手机的感应器在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);  
 

这行代码只要用过类似开发的都应该知道是什么。

getSystemService(String name)可以用来返回一个硬件设备的控制器。比如说LocationManage(和GPS相关用来确定位置的)、 TelephonyManage(查询电话相关内容,比如说IMEI码)、AudioManager(顾名思义,是视频播放用的)等等。。。具体可以观看SDK文档里边 Activity的讲解。在线文档在这里(偶尔需要翻墙)

 

得到重力感应的硬件控制了,然后我们就应该得到一个Sensor了。

Java代码 
  1. Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ALL);  

 关于这个参数。。。其实挺复杂的。。。。我开始用的是TYPE_ALL,出的是XYZ三条轴线的偏移量,至于其他的大家可以看下边:

下边是官方SDK中对于各种类型的解析(粗体红字是我加上去的 )

 

<!-- =========== ENUM CONSTANT SUMMARY =========== -->

ConstantsintTYPE_ACCELEROMETERA constant describing an accelerometer sensor type.加速度intTYPE_ALLA constant describing all sensor types.所有类型,NexusOne默认为 加速度intTYPE_GYROSCOPEA constant describing a gyroscope sensor type回转仪(这个不太懂)intTYPE_LIGHTA constant describing an light sensor type.光线感应吗intTYPE_MAGNETIC_FIELDA constant describing a magnetic field sensor type.磁场intTYPE_ORIENTATIONA constant describing an orientation sensor type.定向(指北针)和角度intTYPE_PRESSUREA constant describing a pressure sensor type压力计intTYPE_PROXIMITYA constant describing an proximity sensor type.距离?不太懂intTYPE_TEMPERATUREA 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. }  
 

所有最基本的三维坐标系有三个轴: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.         };  

在这里我把数字放大了,我预先定义了一个变量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);  

三个参数分别是监听,感应装置,和灵敏度。

 

灵敏度分为:

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度,那么就是水平了!

 


http://sunnyday55555.javaeye.com/blog/481723


android中的很多游戏的游戏都使用了重力感应的技术,但其api demo却并没有重力感应的实例(不知道是不是我没找到,找到的朋友麻烦告诉我一下,谢谢),因为开发的需要,就研究了一下重力感应这方面,因为网上关于这方面的东西比较少,所以写出来跟大家交流一下,算是抛砖引玉吧。(ps.因为重力感应式需要真机才能测试的,所以,下面提供的demo程序只能在真机上跑。) 




因为官方说明比较含糊难懂,我用最简单的方式讲一下android重力感应系统的坐标系 



http://dl.javaeye.com/upload/picture/pic/44045/8aff83b0-0a37-3870-979b-1b329569452d.jpg 

 


以屏幕的左下方为原点(2d编程的时候,是以屏幕左上方为原点的,这个值得注意一下),箭头指向的方向为正。从-10到10,以浮点数为等级单位,想象一下以下情形: 


手机屏幕向上(z轴朝天)水平放置的时侯,(x,y,z)的值分别为(0,0,10); 


手机屏幕向下(z轴朝地)水平放置的时侯,(x,y,z)的值分别为(0,0,-10); 


手机屏幕向左侧放(x轴朝天)的时候,(x,y,z)的值分别为(10,0,0); 


手机竖直(y轴朝天)向上的时候,(x,y,z)的值分别为(0,10,0); 


其他的如此类推,规律就是:朝天的就是正数,朝地的就是负数。利用x,y,z三个值求三角函数,就可以精确检测手机的运动状态了。 




接下来,用最短的代码完成功能,程序效果就是在title上面输出x,y,z的值。 


Java代码 

package com.ray.test;    

import android.app.Activity;    

import android.os.Bundle;    

import android.hardware.SensorManager;    

import android.hardware.Sensor;    

import android.hardware.SensorEventListener;    

import android.hardware.SensorEvent;    

    

    

ublic class SensorTest extends Activity {    

   private SensorManager sensorMgr;    

   Sensor sensor = sensorMgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);    

   private float x, y, z;    

   protected void onCreate(Bundle savedInstanceState) {    

   super.onCreate(savedInstanceState);    

   sensorMgr = (SensorManager) getSystemService(SENSOR_SERVICE);    

       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];    

             setTitle("x="+(int)x+","+"y="+(int)y+","+"z="+(int)z);    

          }    

              

           public void onAccuracyChanged(Sensor s, int accuracy) {    

           }    

       };    

      //注册listener,第三个参数是检测的精确度    

       sensorMgr.registerListener(lsn, sensor, SensorManager.SENSOR_DELAY_GAME);    

   }    

       

    


原创粉丝点击