引言:俄罗斯方块这款游戏是由苏联的游戏制作人阿列克谢·帕基特诺夫在1985年发明的,那年偶才出生,这23年间相信这款老游戏被无数新人重做过,所以说我们是站在巨人的肩上的,我们在继承他们的成果的同时,企求我们能不断创新,让这款经典游戏更好玩,让更多的人喜欢玩!我之所以把它贴在我博客里,是想让自己能够在这个项目中得到更好的锻炼,各位大牛不妨多拍拍砖,你们所拍的每一砖都是我前进的动力!我会把每天的项目进度都贴在这里。。。
1.关于“蓝牙技术”
蓝牙技术应用了plonk and play 的概念,有点类似“即插即用”(打个比方)。蓝牙技术是一种无线数据与语音通讯的开放性标准,它以近距离无线连接为基础,为固定与移动设备通信环境建立一个特别连接,其有效传输距离是33英尺(10米)。 想详细了解蓝牙技术的朋友请自己Google一下,如果不想Google可以看这个“
百度百科全书——蓝牙技术
”。
2.JSR82(JABWT)规范
02年4月5日,JCP发布了J2ME平台的蓝牙API规范JSR82(Java蓝牙无线技术APIs,Java APIs for Bluetooth Wireless Technology).JSR82规范定义的API中包括21个类和接口,最小需求是CLDC,CDC是CLDC的超集(偶的理解),所以JABWT可以同时在CLDC和CDC上实现,JSR82在核心协议中支持L2CAP、RFCOMM、SDP和OBEX。从便于开发的角度将API分为设备/服务发现(Discovery)、通信(Communication)和设备管理(DeviceManagement)3大类。发现类包括设备发现、服务发现和服务注册的类和接口;通信类包括在串行剖面层次、RFCOMM层次、L2CAP层次和OBEX层次建立连接和使用连接的类和接口;设备管理类包括代表控制和管理的类和接口。这使得我们在开发的时候不再需要很多蓝牙技术的细节;而是可以从功能角度来理解蓝牙技术,在响应的功能类中选择合适的API和接口。
基于JSR82的协议栈如图1所示,Bluetooth Host Protocol Stack(software)部分为JSR82规范提供给java平台开发者的蓝牙软件协议栈。
![](/upload/picture/pic/23563/fd082a26-78c9-391d-bd6a-f286d6733c9d.jpg)
图1:基于JSR82的协议栈
典型的蓝牙应用程序实例 一个开启蓝牙功能的应用可以作为一个服务端或是一个客户端-- 一个服务的提供者或是消费者,或者它可以作为一个真正的点对点终端同时表现出服务和客户的行为。图2所示一个蓝牙规范用例:
![](/upload/picture/pic/23565/84a9fa21-34de-3071-8fcd-fe9f8a3b7d9a.jpg)
图2:一个典型的具有蓝牙功能的实际用例
.初始化-- 所有具备蓝牙功能的应用程序必须先要初始化蓝牙栈。
.客户端-- 一个客户对远端服务进行消费。首先它要发现所有附近的设备,然后对于每一个发现的设备搜索它感兴趣的服务。
.服务器端-- 一个为客户端提供服务的服务器。它在服务发现数据库(SDDB)中对客户端进行注册,对他们进行有效广播。然后等待引入的连接,在他们进入时接受他们并为他们提供服务。最后,当不再需要服务时,应用程序会在服务发现数据库(SDDB)中将他们移除。
![](/upload/picture/pic/23561/fb013e84-c29d-3f1b-8e2d-75bb805983c9.jpg)
图 3: 蓝牙应用程序活动图
蓝牙应用程序中的元素
图4显示了在MIDlet中一个典型蓝牙功能应用程序中的一些元素:
![](/upload/picture/pic/23553/ce667832-cbc5-310d-b8a7-5f17ca777a27.jpg)
图4: 具有蓝牙功能的 MIDlet (高端组织)
中间的是核心应用程序My Bluetooth MIDlet,它扩展自javax.microedition.midlet.MIDlet。没有显示出来的还有MIDlet中实现的javax.microedition.lcdui.CommandListener以监听从用户接口中输入的命令。应用程序使用的剩余的类和接口都包含在了蓝牙规范中,像设备发现和服务,连接和服务消费,还有广播和提供服务。
使用诸如MVC等设计模式是很好的实践。MVC把应用程序分解成用户接口(视图),应用程序行为和导航(控制器),以及数据(模型),当然在我们的案例中还要加上蓝牙API的支撑类和接口。像将分离的客户端、服务端行为构建成独立的类以便以后可以重用这些组件,也是很好的设计。
3.Java蓝牙API核心概述
在JSR82规范中已说过了Java蓝牙API可以被分解为三个部分:发现、设备管理和通信。
a.蓝牙发现API
客户端程序使用蓝牙发现API以搜索在其附近的设备和服务。服务代理类(DiscoveryAgent)同时支持设备与服务的发现。当设备和服务被发现时,想得到通知的客户端应用程序必须实现并注册DiscoveryListener接口,这个接口定义了设备发现通知和服务发现通知的回调。
发现代理(DiscoveryAgent)与蓝牙客户端应用程序之间是典型的一对一的关系:
![](/upload/picture/pic/23559/23a4dd4d-37c8-3f6a-bc41-3959d497578f.jpg)
图 5: DiscoveryAgent类和DiscoveryListener接口
b.设备发现API
你使用DiscoveryAgent类的"设备发现"方法来开始和取消设备发现:
.retrieveDevices()重新获得已经发现或者附近的已知设备
.startInquiry() 启动发现附近设备,也叫inquiry
.cancelInquiry()取消当前进行的任何请求
蓝牙发现代理在请求阶段的不同时候会分别调用DiscoveryListener(发现监听器)不同的回调方法:
.deviceDiscovered() 指出是否有设备被发现。
.inquiryCompleted() 指出是否请求已经成功、触发一个错误或已被取消。
图6中的状态图表阐明了设备发现的状态改变结束于相应的回调方法的返回。
![](/upload/picture/pic/23567/4f5b5478-68df-3bbf-94b2-dbd661320734.jpg)
图 6: 设备发现状态表
设备发现以调用startInquiry()函数开始。在请求进行时,蓝牙发现代理会在适当的时候调用回调方法DeviceDiscovered()和inquiryCompleted()。
c.服务发现API 你可以使用发现代理的服务发现方法来开始或取消服务发现:
. selectService()启动服务发现搜索。(原文有误,根据API手册应为尝试定位一个服务)
. searchServices()启动服务发现搜索。
. cancelServiceSearch()取消在正在进行中的任何的服务发现搜索操作。
蓝牙发现代理在服务发现阶段的不同时候会分别调用DiscoveryListener的服务发现回调方法:
. servicesDiscovered() 表示是否服务已被发现。
. serviceSearchCompleted()表示服务发现是否已经完成。
图7阐明了服务发现的状态改变结束于DiscoveryListener的回调方法的返回。
![](/upload/picture/pic/23569/8af8f41f-a10f-34b1-bca2-c4e0cad0b0d2.jpg)
图 7: 服务发现状态图表
服务发现开始于对searchServices()的调用。当服务搜索进行时,蓝牙发现代理会在适当的时候回调servicesDiscovered()和 serviceSearchCompleted()方法。
除了DiscoveryAgent和 DiscoveryListener了,你在服务发现过程中还要使用到的类有UUID,ServiceRecord以及DataElement等。
UUID类
在蓝牙中,每个服务和服务属性都唯一地由"全球唯一标识符" (UUID)来校验。正如它的名字所暗示的,每一个这样的标识符都要在时空上保证唯一。UUID类可表现为短整形(16或32位)和长整形(128位)UUID。他提供了分别利用String和16位或32位数值来创建类的构造函数,提供了一个可以比较两个UUID(如果两个都是128位)的方法,还有一个可以转换一个UUID为一个字符串的方法。UUID实例是不可改变的(immutable),只有被UUID标示的服务可以被发现。
在Linux下你用一个命令uuidgen -t可以生成一个UUID值;在Windows下则执行命令uuidgen 。UUID看起来就像如下的这个形式:2d266186-01fb-47c2-8d9f-10b8ec891363。当使用生成的UUID去创建一个UUID对象,你可以去掉连字符。
SDDB和ServiceRecord接口 在服务发现的中心是服务发现数据库(SDDB)和服务发现协议(SDP)。SDDB由蓝牙实现负责维护的数据库。它包含了服务记录(service records),后者代表了对客户端有效的服务。SDP对于基于JABWT应用程序来说是透明的;可以这么说,SDP是用于服务发现的。为重新获取服务纪录,一个本地设备SDP客户端会向一个远端设备上SDP服务器发出请求。
![](/upload/picture/pic/23555/32e0b281-68d4-30b9-8c76-26d8fd723f04.jpg)
图 8: SDDB
每一笔服务记录都会由一个ServiceRecord的实例来表现。这个记录包含了描述服务细节的属性。这个类提供了几种有用的方法:
.getAttributeIDs() 和 getAttributeValue()方法返回服务记录的属性。
.getConnectionURL()方法获取链接的URL地址给服务器主机来收集服务记录。
.getHostDevice() 方法获取提供服务的远端设备。
.populateRecord() 和 setAttributeValue()方法用来设置设备记录的属性。
.setDeviceServiceClasses()方法设置服务的类。
图9显示了蓝牙本地设备和远端设备,以及SDDB还有服务记录之间的关系:
![](/upload/picture/pic/23557/ac44b4e3-32ea-36d5-863e-6e6542d5b67b.jpg)
图 9: 使用远端设备,SDDB和服务记录进行服务发现
为使服务端可以被客户端来使用,服务应用程序要通过如下方法建立一个服务记录,首先要创建一个连接通知器(connection notifier),然后由调用连接通知器的acceptAndWait()方法来向SDDB中插入记录。服务端程序能够在适当的时候获得记录和更新。客户端应用程序向远端SDDB请求可以使用的服务,会发现服务记录.
未完待续。。。