易码技术论坛

 找回密码
 加入易码
搜索
查看: 1643|回复: 3

[教程] J2ME中Mobile Sensor API使用简介(已完稿,谢谢大家)

[复制链接]
发表于 2009-3-27 00:52:21 | 显示全部楼层 |阅读模式
Mobile Sensor API(jsr256)算是一个比较新的API,目前国内支持该API的手机不多。
鉴于目前国内关于该API的介绍和中文文档不多,本鸟就不自量力地写下拙文,简略地介绍下该API的使用。
1.为何使用
  一般来说,一个API的使用必有其目的。(废话)那么,这个传感器API又有什么大用处呢?
  
    首先,我们知道很多电子产品都有用于感知外部或内部环境的传感器。比如,空调通常有一个温度传感器用来收集周围温度的信息。手机当然也不例外,比如最近新上市的手机基本都配备了重力传感器来实现自动旋转屏幕等功能,更不用说Iphone这样BT的机器更是配备了环境光度传感器等一系列传感器。
  如果你对wii这类新型态的家用游戏机一点都不感到陌生的话,相信你一定会对使用各类传感器来增强游戏体验这点感到兴奋。(当然,J2ME不仅仅应用于手机,传感器也并不仅用于游戏,但本文仅探讨其在手机游戏中的运用)
  没错,利用好传感器这个新资源我们能设计出更有意思的游戏!
2.使用之前
    和其他任何可选包一样,在使用Mobile Sensor API之前应该对手机是否支持该可选包进行查询。我们知道在J2ME当中使用System.getProperty(String)方法可以查询系统属性,所以在使用该API之前,可以先用:
    String version = System.getProperty("microedition.sensor.version");
这条语句来获得该手机的Mobile Sensor API版本,当字符串version不为null时,表明手机系统支持该API。
3.一些概念
    为了描述传感器和其传输数据的方式,Mobile Sensor API当中定义Sensor、Channel、Data等概念。
具体来说,一个Sensor代表一个传感器,关于这个传感器的信息由SensorInofo类来说明;一个Channel相当于一条传输通道(我不知道还有什么其他说法),其信息由ChannelInfor类说明;而Data类是传感器传输的数据的类(不管这个数据是什么类型的,int或者folat,都是用Data类来包含该数据)。(其他还有Condition等概念,但是这些类我们不常使用,请参考jsr256来获得关于它们的具体信息)
    Mobile Sensor API还定义了SensorManager类来总管传感器。
    介绍了这些概念,是不是觉得太抽象了呢,现在我们就重力传感器的例子来说明吧。
    因为重力传感器测量了3个方向(空间中x,y,z三个轴方向)的重力分布情况,所以它有3条用于传输的数据通道(Channel),当然每条数据通道都可以传输数据(Data)。Data这个类能包含所有类型的数据,比如当传感器回传的数据是int类型的时候,可以使用Data.getIntValues()方法来获得int类型的数据。需要注意的是,为了顾及传感器可能的所有数据(估计是某些传感器一个通道能同时传输多组数据),Data这个类当中这些方法返回的并不是一个数,而是一个数组(比如一个int数组)。
4.查找传感器   
    正如前文所述,SensorManager类是用于总管所有传感器的类(有些类似Mobile Media API当中的Manager类),所以在使用传感器之前,获得该传感器信息的查找工作自然由它负责。使用方法SensorManager.findSensors(null,null)将会获得一个SensorInfo数组,其中包含该硬件本身可以提供给J2ME访问的所有传感器的信息。即:
    SensorInfo[] si =  SensorManager.findSensors(null,null);
用这条语句可以获得所有传感器的信息,这些信息包含在si数组当中。
接下来就介绍下SensorInfo这个类了。这个类包含了传感器的信息,当中对我们来说最为重要的就是以下几个:
ChannelInfo:可以用SensorInfo.getChannelInfos()方法获得,说明传感器的通道信息(可以理解为有多少个通道)。
Quantity:可以用SensorInfo.getQuantity()方法获得,可以帮助我们查找需要的传感器(这个属性有些类似传感器的名字,但是它偏偏不是,我直接把它当name来理解了,至于为什么,往下看你就知道了,具体它不是名字的原因可以参照jsr文档)。
URL:可以用SensorInfo.getUrl()方法获得,传感器在设备中的url地址,我们访问该传感器必需的信息。
假设下面我们要查找重力传感器的URL(有了URL我们才可以连接到这个传感器上),我们可以这么写:
SensorInfo[] si =  SensorManager.findSensors(null,null);
String url = "";
for(i=0;i<si.lenght;i++){
  if(si.getQuantity == "acceleration"){//acceleration这个词是“加速度”的意思,这个重力传感器也叫加速度传感器
    url = si.getUrl();
    break;
  }
}
这下你知道我为什么说我把Quantity这个属性当作name来理解了吧,比较的明明就是传感器的名字嘛(小声吐槽:其实是类型的说)!
可能有的同学要提问了,找个传感器这么大费周章,还要一个一个历遍,有没有更简单的方法?
答案是:有,同学你太有才了!可是要解释这个实在很麻烦,我都想直接给代码算了。
这个有捷径的方法就是:
SensorInfo[] si = SensorManager.findSensors ( "acceleration" , SensorInfo.CONTEXT_TYPE_USER ) ;
其中si[0]就是重力传感器的的SensorInfo了。
咦,这是什么碗糕?因为在SensorInfo当中,传感器被按照属性分类了,而且同一个传感器并不是只有一个属性,而是拥有复合属性。
这句话用常识来解释说就好比“男同学”同时具有“男性”和“学生”两个属性这样,本鸟这个比喻不知道是不是能直接让你明白过来呢?
如果说用SensorManager.findSensors (null,null)方法像挨家挨户查户口那样去找人,麻烦又浪费行数的话,用SensorManager.findSensors (quantity,contextType)就像直接按类别筛选来找。
那么关于这个CONTEXT_TYPE的定义呢?
汗,这个实在太麻烦了,你们请直接去看jsr,本鸟没那耐心为它浪费字节,再说,目前最有用的重力传感器的查找方法我都给你们了,如果你们不是像本鸟一样有兴趣做个模拟系统的话应该足够用了。
(众人:喂喂!)
你们的提议被驳回!无限期驳回!就是这样,继续下一个议题。
5.连接传感器
我们已经找到了想要的传感器的URL了,下一步当然是打开连接它,让它开始为我们服务啦!
废话少说,赶快征服这块蛮荒之地吧!
SensorConnection SCC = (SensorConnection)Connector.open(url);
用这个语句就能打开对应的传感器了,因为这个语句可能抛出异常,所以我们要把它包围在try{}catch(){}块当中。
但凡用过Connector的人应该都知道,这个语句调用爱抛异常,我们已经见怪不怪了。
有人会问SensorConnection又是什么玩意?顾名思义,打开文件要用fileConnection,打开传感器当然是用SensorConnection咯。
SensorConnection类是我们操作传感器的主要类,和fileConnection相似,SensorConnection提供了我们所需的功能,最重要的就是它的getChannel(ChannelInfo)和getData(int bufferSize)方法了。(返回什么一看就知道了吧?)
不过以上两个方法对我们来说都用处不大。
  (吐槽:那你还说来干嘛?!)
因为那两个方法不但用起来麻烦,而且得到的值用处也不大,为什么我那么说呢,因为最重要的不是某一时刻的值,而是连续的值。
比如说用重力传感器来设计游戏,一个仅仅会探知当前重力分布的状况的程序没办法给我们更好的体验,因为根据连续的值的计算,我们甚至可以根据玩家挥舞手机的速度来调整游戏中玩家的动作。
(这一定是一个很热血的游戏,居然把手机挥舞起来,不小心脱手怎么办?汗)
因此,下面要介绍的接口就派上用场了。
6.接口DataListener
    大家热烈鼓掌欢迎DataListener登场!
    (四处响起稀稀拉拉的掌声)
    喂喂,好歹人家是给你们卖命的,掌声热烈点行不行?
    (有人先是楞了一下,然后又不大情愿地动起手来,掌声还是和小雨一样……)
   算了,DataListener这个接口就是提供来监视传感器的连续的值的。
   (面露正色)
     继承这个接口的同时要继承抽象的方法public void dataReceived(SensorConnection sensor, Data[] data, boolean isLost),大家看到这个应该知道是拿来干什么的了吧?
    没错,正是用这个来收集数据的,需要储存的数据通过重写这个方法来实现。
    下面给出我自己重写的这个方法:(用于重力传感器)
    public void dataReceived(SensorConnection sensor, Data[] data, boolean isLost) {
    // TODO 自动生成方法存根
    gravityData[0] = data[0].getIntValues()[0];
    gravityData[1] = data[1].getIntValues()[0];
    gravityData[2] = data[2].getIntValues()[0];
   }
   以上的Data类通过getIntValues()方法能获得int类型的数值。
  当然,既然这个接口是Linster,必须要有设置和移除监听器的方法,这里看名字就知道是SensorConnection.setDataListener(DataLister, int);和SensorConnection.removeDataListener();
设置监听器的时候要同时设置数据缓存的大小,当然越大的缓存测得的值就越少出现峰值,但是一般情况下我们不需要太精确地知道手机的姿态,所以为了方便通常设为1。
继承了DataListener的接口之后,很自然就会这样设置:
SensorConnection.setDataListener(this, i1);

好了,基本教程就写到这里了,剩下的就靠大家自己看JSR文件了!

[ 本帖最后由 绿鸟 于 2009-4-9 17:40 编辑 ]

评分

参与人数 1小红花 +5 收起 理由
jason + 5 java已经忘光了

查看全部评分

发表于 2009-3-27 13:09:57 | 显示全部楼层
哈哈.我来占沙发了...
顶...
发表于 2009-3-28 11:15:53 | 显示全部楼层
看不懂,纯顶
 楼主| 发表于 2009-4-9 17:41:51 | 显示全部楼层
最后居然超一楼的字数上限了,果然没办法呢,只好删掉一些俏皮话了!
完稿了,真谢谢大家,拖了很久。
另外想看完整版的请去看我QQ空间(其实没有多什么,删了些无关紧要的东西而已,呵呵)……
以上。
您需要登录后才可以回帖 登录 | 加入易码

本版积分规则

Archiver|手机版|小黑屋|EMAX Studio

GMT+8, 2024-3-28 19:30 , Processed in 0.011149 second(s), 19 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表