您好,欢迎来到五一七教育网。
搜索
您的当前位置:首页J2ME蓝牙(bluetooth)实战入门

J2ME蓝牙(bluetooth)实战入门

来源:五一七教育网
J2ME蓝牙(bluetooth)实战入门

0

View: 2106 |

开发技术 - 程序设

Author: 一滴蔚蓝色 |

Digg: 0

Date: 2007-07-29 |

计 |

概述

目前,很多手机已经具备了蓝牙功能。虽然MIDP2.0没有包括蓝牙API,但是JCP定义了

JSR82, Java APIs for Bluetooth Wireless Technology (JABWT).这是一个可选API,很多支持MIDP2.0的手机已经实现了,比如

Nokia 6600, Nokia 6670,Nokia7610等等。对于一个开发者来说,如果目标平台支持JSR82的话,在制作联网对战类型游戏或者应用的时候,蓝牙是一个相当不错的选择。本文给出了一个最简单的蓝牙应用的J2ME程序,用以帮助开发者快速的掌握JSR82。该程序分别在2台蓝牙设备上安装后,一台设备作为服务端先运行,一台设备作为客户端后运行。在服务端上我们发布了一个服务,该服务的功能是把客户端发过来的字符串转变为大写字符串。客户端起动并搜索到服务端的服务后,我们就可以从客户端的输入框里输入任意的字符串,发送到服务端去,同时观察服务端的反馈结果。

本文并不具体讲述蓝牙的运行机制和JSR82的API结构,关于这些知识点,请参考本文的参考资料一节,这些参考资料会给你一个权威的精确的解释。

实例代码

该程序包括3个java文件。一个是MIDlet,另外2个为服务端GUI和客户端GUI。该程序已经在wtk22模拟器和Nokia 6600,Nokia 6670两款手机上测试通过。

StupidBTMIDlet.java

1. 2. 3. 4. 5. 6. 7. 8. 9.

import javax.microedition.lcdui.Alert; import javax.microedition.lcdui.AlertType; import javax.microedition.lcdui.Command;

import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Display; import javax.microedition.lcdui.Displayable; import javax.microedition.lcdui.List; import javax.microedition.midlet.MIDlet;

import javax.microedition.midlet.MIDletStateChangeException; 10. /**

11. * @author Jagie 12. * 13. * MIDlet 14. */

15. public class StupidBTMIDlet extends MIDlet implements C

ommandListener { 16. List list; 17. ServerBox sb; 18. ClientBox cb; 19. /*

20. * (non-Javadoc) 21. *

22. * @see javax.microedition.midlet.MIDlet#startApp() 23. */

24. protected void startApp() throws MIDletStateChangeExc

eption {

25. list = new List(\"傻瓜蓝牙入门\", List.IMPLICIT); 26. list.append(\"Client\", null); 27. list.append(\"Server\", null); 28. list.setCommandListener(this);

29. Display.getDisplay(this).setCurrent(list); 30. } 31. 32. /**

33. * debug方法

34. * @param s 要显示的字串 35. */

36. public void showString(java/lang/String.java.html\"

target=\"_blank\">String s) {

37. Displayable dp = Display.getDisplay(this).getCurrent(); 38. Alert al = new Alert(null, s, null, AlertType.INFO); 39. al.setTimeout(2000);

40. Display.getDisplay(this).setCurrent(al, dp); 41. } 42. 43. /**

44. * 显示主菜单 45. * 46. */

47. public void showMainMenu() {

48. Display.getDisplay(this).setCurrent(list); 49. } 50.

51. protected void pauseApp() {

52. // TODO Auto-generated method stub 53. }

54. public void commandAction(Command com, Displayable d

isp) {

55. if (com == List.SELECT_COMMAND) { 56. List list = (List) disp;

57. int index = list.getSelectedIndex(); 58. if (index == 1) { 59. if (sb == null) {

60. sb = new ServerBox(this); 61. }

62. sb.setString(null);

63. Display.getDisplay(this).setCurrent(sb); . } else {

65. //每次都生成新的客户端实例 66. cb = null;

67. java/lang/System.java.html\"

target=\"_blank\">System.gc(); 68. cb = new ClientBox(this);

69. Display.getDisplay(this).setCurrent(cb); 70. } 71. } 72. }

73. protected void destroyApp(boolean arg0) throws MIDlet

StateChangeException {

74. // TODO Auto-generated method stub 75. } 76. }

ClientBox.java

1.

import java.io.java/io/DataInputStream.java.html\" target=\"_blank\">DataInputStream; 2.

import java.io.java/io/DataOutputStream.java.html\" target=\"_blank\">DataOutputStream; 3.

import java.io.java/io/IOException.java.html\" target=\"_blank\">IOException; 4.

import java.util.java/util/Vector.java.html\" target=\"_blank\">Vector; 5. 6. 7. 8. 9.

import javax.microedition.io.Connector;

import javax.microedition.io.StreamConnection; import javax.microedition.lcdui.Command;

import javax.microedition.lcdui.CommandListener; import javax.microedition.lcdui.Displayable;

10. import javax.microedition.lcdui.Form; 11. import javax.microedition.lcdui.Gauge; 12. import javax.microedition.lcdui.StringItem; 13. import javax.microedition.lcdui.TextField; 14. //jsr082 API

15. import javax.bluetooth.BluetoothStateException; 16. import javax.bluetooth.DeviceClass; 17. import javax.bluetooth.DiscoveryAgent; 18. import javax.bluetooth.DiscoveryListener; 19. import javax.bluetooth.LocalDevice;

20. import javax.bluetooth.RemoteDevice; 21. import javax.bluetooth.ServiceRecord; 22. import javax.bluetooth.UUID; 23. /**

24. * 客户端GUI 25. * @author Jagie 26. *

27. * TODO To change the template for this generated type com

ment go to

28. * Window - Preferences - Java - Code Style - Code Templates 29. */

30. public class ClientBox extends Form implements java/lan

g/Runnable.java.html\"

target=\"_blank\">Runnable, CommandListener, 31. DiscoveryListener { 32.

33. //字串输入框

34. TextField input = new TextField(null, \"\", 50, TextField.ANY

);

35. //loger

36. StringItem result = new StringItem(\"结果:\", \"\"); 37. private DiscoveryAgent discoveryAgent; 38.

39. private UUID[] uuidSet; 40. //响应服务的UUID

41. private static final UUID ECHO_SERVER_UUID = new UU

ID(

42. \"F0E0D0C0B0A000908070605040302010\", false); 43. //设备集合

44. java/util/Vector.java.html\"

target=\"_blank\">Vector devices = new java/util/Vector.java.html\" target=\"_blank\">Vector(); 45. //服务集合

46. java/util/Vector.java.html\"

target=\"_blank\">Vector records = new java/util/Vector.java.html\" target=\"_blank\">Vector(); 47.

48. //服务搜索的事务id集合 49. int[] transIDs;

50. StupidBTMIDlet midlet;

51. public ClientBox(StupidBTMIDlet midlet) { 52. super(\"\");

53. this.midlet=midlet; 54.

55. this.append(result); 56.

57. this.addCommand(new Command(\"取消

\",Command.CANCEL,1));

58. this.setCommandListener(this); 59.

60. new java/lang/Thread.java.html\"

target=\"_blank\">Thread(this).start(); 61. } 62.

63. public void commandAction(Command arg0, Displayable a

rg1) {

. if(arg0.getCommandType()==Command.CANCEL){ 65. midlet.showMainMenu();

66. }else{

67. //匿名内部Thread,访问远程服务。 68. java/lang/Thread.java.html\"

target=\"_blank\">Thread fetchThread=new java/lang/Thread.java.html\" target=\"_blank\">Thread(){ 69. public void run(){

70. for(int i=0;i71. ServiceRecord sr=(ServiceRecord)records.ele

mentAt(i);

72. if(accessService(sr)){ 73. //访问到一个可用的服务即可 74. break; 75. } 76. } 77. } 78. };

79. fetchThread.start(); 80. } 81. 82. } 83. 84.

85. private boolean accessService(ServiceRecord sr){ 86. boolean result=false; 87. try {

88. java/lang/String.java.html\"

target=\"_blank\">String url = sr.getConnectionURL( . ServiceRecord.NOAUTHENTICATE_NOENCRYPT,

false);

90. StreamConnection conn = (StreamConnection) Con

nector.open(url); 91.

92. java/io/DataOutputStream.java.html\"

target=\"_blank\">DataOutputStream dos=conn.openDataOutputStream();

93. dos.writeUTF(input.getString()); 94. dos.close();

95. java/io/DataInputStream.java.html\"

target=\"_blank\">DataInputStream dis=conn.openDataInputStream();

96. java/lang/String.java.html\"

target=\"_blank\">String echo=dis.readUTF(); 97. dis.close();

98. showInfo(\"反馈结果是:\"+echo); 99. result=true; 100.

101. } catch (java/io/IOException.java.html\"

target=\"_blank\">IOException e) { 102. 103. }

104. return result; 105. }

106. public synchronized void run() { 107. //发现设备和服务的过程中,给用户以Gauge

108. Gauge g=new Gauge(null,false,Gauge.INDEFINITE,Ga

uge.CONTINUOUS_RUNNING); 109. this.append(g);

110. showInfo(\"蓝牙初始化...\");

111. boolean isBTReady = false; 112. try {

113. LocalDevice localDevice = LocalDevice.getLocalDevice

();

114. discoveryAgent = localDevice.getDiscoveryAgent(); 115. isBTReady = true;

116. } catch (java/lang/Exception.java.html\"

target=\"_blank\">Exception e) { 117. e.printStackTrace(); 118. }

119. if (!isBTReady) {

120. showInfo(\"蓝牙不可用\"); 121. //删除Gauge 122. this.delete(1); 123. return; 124. }

125. uuidSet = new UUID[2]; 126. //标志我们的响应服务的UUID集合 127. uuidSet[0] = new UUID(0x1101); 128. uuidSet[1] = ECHO_SERVER_UUID; 129. 130. try {

131. discoveryAgent.startInquiry(DiscoveryAgent.GIAC, th

is);

132. } catch (BluetoothStateException e) { 133. } 134. try {

135. //阻塞,由inquiryCompleted()回调方法唤醒 136. wait();

137. } catch (java/lang/InterruptedException.java.html

\" target=\"_blank\">InterruptedException e1) { 138.

139. e1.printStackTrace(); 140. }

141. showInfo(\"设备搜索完毕,共找到\"+devices.size()+\"个设备,开

始搜索服务\");

142. transIDs = new int[devices.size()]; 143. for (int i = 0; i < devices.size(); i++) {

144. RemoteDevice rd = (RemoteDevice) devices.element

At(i);

145. try {

146. //记录每一次服务搜索的事务id

147. transIDs[i] = discoveryAgent.searchServices(null,

uuidSet,

148. rd, this);

149. } catch (BluetoothStateException e) { 150. continue; 151. } 152. } 153. 154. try {

155. //阻塞,由serviceSearchCompleted()回调方法在所有设备都搜索完的情况下唤醒 156. wait();

157. } catch (java/lang/InterruptedException.java.html

\" target=\"_blank\">InterruptedException e1) { 158. e1.printStackTrace(); 159. }

160.

161. showInfo(\"服务搜索完毕,共找到\"+records.size()+\"个服务,准

备发送请求\");

162. if(records.size()>0){ 163. this.append(input);

1. this.addCommand(new Command(\"发送

\",Command.OK,0)); 165. } 166.

167. //删除Gauge 168. this.delete(1); 169. 170. } 171. 172. /** 173. * debug 174. * @param s 175. */ 176.

177. private void showInfo(java/lang/String.java.html\"

target=\"_blank\">String s){

178. java/lang/StringBuffer.java.html\"

target=\"_blank\">StringBuffer sb=new java/lang/StringBuffer.java.html\"

target=\"_blank\">StringBuffer(result.getText()); 179. if(sb.length()>0){ 180. sb.append(\"\\n\"); 181. }

182. sb.append(s);

183. result.setText(sb.toString()); 184. } 185. 186. /** 187. * 回调方法 188. */

1. public void deviceDiscovered(RemoteDevice btDevice, De

viceClass cod) {

190. if (devices.indexOf(btDevice) == -1) { 191. devices.addElement(btDevice); 192. } 193. } 194. /**

195. * 回调方法,唤醒初始化线程 196. */

197. public void inquiryCompleted(int discType) { 198. synchronized (this) { 199. notify(); 200. } 201. } 202. /** 203. * 回调方法 204. */

205. public void servicesDiscovered(int transID, ServiceRecord

[] servRecord) {

206. for (int i = 0; i < servRecord.length; i++) { 207. records.addElement(servRecord[i]); 208. } 209. }

210. 211. /**

212. * 回调方法,唤醒初始化线程 213. */

214. public void serviceSearchCompleted(int transID, int resp

Code) { 215.

216. for (int i = 0; i < transIDs.length; i++) { 217. if (transIDs[i] == transID) { 218. transIDs[i] = -1; 219. break; 220. } 221. } 222.

223. //如果所有的设备都已经搜索服务完毕,则唤醒初始化线程。 224. boolean finished = true;

225. for (int i = 0; i < transIDs.length; i++) { 226. if (transIDs[i] != -1) { 227. finished = false; 228. break; 229. } 230. }

231. if (finished) {

232. synchronized (this) { 233. notify(); 234. } 235. } 236. } 237. }

ServerBox.java

1.

import java.io.java/io/DataInputStream.java.html\" target=\"_blank\">DataInputStream; 2.

import java.io.java/io/DataOutputStream.java.html\" target=\"_blank\">DataOutputStream; 3.

import java.io.java/io/IOException.java.html\" target=\"_blank\">IOException; 4.

import java.util.java/util/Vector.java.html\" target=\"_blank\">Vector; 5. 6. 7. 8. 9.

import javax.bluetooth.DiscoveryAgent; import javax.bluetooth.LocalDevice; import javax.bluetooth.ServiceRecord; import javax.bluetooth.UUID;

import javax.microedition.io.Connector;

10. import javax.microedition.io.StreamConnection; 11. import javax.microedition.io.StreamConnectionNotifier; 12. import javax.microedition.lcdui.Command;

13. import javax.microedition.lcdui.CommandListener; 14. import javax.microedition.lcdui.Displayable; 15. import javax.microedition.lcdui.TextBox; 16. import javax.microedition.lcdui.TextField; 17. /**

18. * 服务端GUI 19. * @author Jagie 20. *

21. * TODO To change the template for this generated type com

ment go to

22. * Window - Preferences - Java - Code Style - Code Templates 23. */

24. public class ServerBox extends TextBox implements java

/lang/Runnable.java.html\"

target=\"_blank\">Runnable, CommandListener { 25. Command com_pub = new Command(\"开启服务

\", Command.OK, 0);

26. Command com_cancel = new Command(\"终止服务

\", Command.CANCEL, 0);

27. Command com_back = new Command(\"返回

\", Command.BACK, 1); 28. LocalDevice localDevice;

29. StreamConnectionNotifier notifier; 30. ServiceRecord record; 31. boolean isClosed; 32. ClientProcessor processor; 33. StupidBTMIDlet midlet; 34. //响应服务的uuid

35. private static final UUID ECHO_SERVER_UUID = new UU

ID(

36. \"F0E0D0C0B0A000908070605040302010\", false); 37. public ServerBox(StupidBTMIDlet midlet) { 38. super(null, \"\", 500, TextField.ANY); 39. this.midlet = midlet;

40. this.addCommand(com_pub); 41. this.addCommand(com_back); 42. this.setCommandListener(this); 43. }

44. public void run() {

45. boolean isBTReady = false; 46. try {

47. localDevice = LocalDevice.getLocalDevice(); 48. if (!localDevice.setDiscoverable(DiscoveryAgent.GIAC

)) {

49. showInfo(\"无法设置设备发现模式\"); 50. return; 51. }

52. // prepare a URL to create a notifier 53. java/lang/StringBuffer.java.html\"

target=\"_blank\">StringBuffer url = new java/lang/StringBuffer.java.html\"

target=\"_blank\">StringBuffer(\"btspp://\"); 54. // indicate this is a server

55. url.append(\"localhost\").append(:); 56. // add the UUID to identify this service 57. url.append(ECHO_SERVER_UUID.toString()); 58. // add the name for our service 59. url.append(\";name=Echo Server\");

60. // request all of the client not to be authorized 61. // some devices fail on authorize=true 62. url.append(\";authorize=false\"); 63. // create notifier now

. notifier = (StreamConnectionNotifier) Connector 65. .open(url.toString());

66. record = localDevice.getRecord(notifier); 67. // remember weve reached this point. 68. isBTReady = true;

69. } catch (java/lang/Exception.java.html\"

target=\"_blank\">Exception e) { 70. e.printStackTrace(); 71. 72. }

73. // nothing to do if no bluetooth available 74. if (isBTReady) {

75. showInfo(\"初始化成功,等待连接\"); 76. this.removeCommand(com_pub); 77. this.addCommand(com_cancel); 78. } else {

79. showInfo(\"初始化失败,退出\"); 80. return; 81. }

82. // 生成服务端服务线程对象

83. processor = new ClientProcessor(); 84. // ok, start accepting connections then 85. while (!isClosed) {

86. StreamConnection conn = null; 87. try {

88. conn = notifier.acceptAndOpen(); . } catch (java/io/IOException.java.html\"

target=\"_blank\">IOException e) {

90. // wrong client or interrupted - continue anyway 91. continue; 92. }

93. processor.addConnection(conn); 94. } 95. }

96. public void publish() { 97. isClosed = false; 98. this.setString(null);

99. new java/lang/Thread.java.html\"

target=\"_blank\">Thread(this).start(); 100. }

101. public void cancelService() { 102. isClosed = true; 103. showInfo(\"服务终止\");

104. this.removeCommand(com_cancel); 105. this.addCommand(com_pub); 106. } 107. /*

108. * (non-Javadoc) 109. *

110. * @see javax.microedition.lcdui.CommandListener#comm

andAction(javax.microedition.lcdui.Command, 111. * javax.microedition.lcdui.Displayable) 112. */

113. public void commandAction(Command arg0, Displayable a

rg1) {

114. if (arg0 == com_pub) { 115. //发布service 116. publish();

117. } else if (arg0 == com_cancel) { 118. cancelService(); 119. } else {

120. cancelService();

121. midlet.showMainMenu();

122. } 123. } 124. 125. /**

126. * 内部类,服务端服务线程。 127. * @author Jagie 128. *

129. * TODO To change the template for this generated type co

mment go to

130. * Window - Preferences - Java - Code Style - Code Templa

tes 131. */

132. private class ClientProcessor implements java/lang/Ru

nnable.java.html\" target=\"_blank\">Runnable { 133. private java/lang/Thread.java.html\"

target=\"_blank\">Thread processorThread; 134. private java/util/Vector.java.html\"

target=\"_blank\">Vector queue = new java/util/Vector.java.html\" target=\"_blank\">Vector(); 135. private boolean isOk = true; 136. ClientProcessor() {

137. processorThread = new java/lang/Thread.java.ht

ml\" target=\"_blank\">Thread(this); 138. processorThread.start(); 139. }

140. public void run() { 141. while (!isClosed) { 142. synchronized (this) { 143. if (queue.size() == 0) {

144. try {

145. //阻塞,直到有新客户连接 146. wait();

147. } catch (java/lang/InterruptedException

.java.html\" target=\"_blank\">InterruptedException e) { 148. } 149. } 150. } 151.

152. //处理连接队列

153. StreamConnection conn; 154. synchronized (this) { 155. if (isClosed) { 156. return; 157. }

158. conn = (StreamConnection) queue.firstElement(

);

159. queue.removeElementAt(0); 160. processConnection(conn); 161. } 162. } 163. } 1. 165. /**

166. * 往连接队列添加新连接,同时唤醒处理线程 167. * @param conn 168. */

169. void addConnection(StreamConnection conn) { 170. synchronized (this) {

171. queue.addElement(conn); 172. notify(); 173. } 174. } 175. } 176. /**

177. * 从StreamConnection读取输入 178. * @param conn 179. * @return 180. */

181. private java/lang/String.java.html\"

target=\"_blank\">String readInputString(StreamConnection conn) {

182. java/lang/String.java.html\"

target=\"_blank\">String inputString = null; 183. try {

184. java/io/DataInputStream.java.html\"

target=\"_blank\">DataInputStream dis = conn.openDataInputStream();

185. inputString = dis.readUTF(); 186. dis.close();

187. } catch (java/lang/Exception.java.html\"

target=\"_blank\">Exception e) { 188. e.printStackTrace(); 1. }

190. return inputString; 191. } 192. 193. /**

194. * debug 195. * @param s 196. */

197. private void showInfo(java/lang/String.java.html\"

target=\"_blank\">String s) {

198. java/lang/StringBuffer.java.html\"

target=\"_blank\">StringBuffer sb = new java/lang/StringBuffer.java.html\"

target=\"_blank\">StringBuffer(this.getString()); 199. if (sb.length() > 0) { 200. sb.append(\"\\n\"); 201. }

202. sb.append(s);

203. this.setString(sb.toString()); 204. } 205. 206. /**

207. * 处理客户端连接 208. * @param conn 209. */

210. private void processConnection(StreamConnection conn)

{

211. // 读取输入

212. java/lang/String.java.html\"

target=\"_blank\">String inputString = readInputString(conn);

213. //生成响应

214. java/lang/String.java.html\"

target=\"_blank\">String outputString = inputString.toUpperCase();

215. //输出响应

216. sendOutputData(outputString, conn); 217. try {

218. conn.close();

219. } catch (java/io/IOException.java.html\"

target=\"_blank\">IOException e) { 220. } // ignore

221. showInfo(\"客户端输入:\" + inputString + \已成功响应!\"); 222. } 223. 224. /** 225. * 输出响应

226. * @param outputData 227. * @param conn 228. */

229. private void sendOutputData(java/lang/String.java.ht

ml\"

target=\"_blank\">String outputData, StreamConnection conn) {

230. try {

231. java/io/DataOutputStream.java.html\"

target=\"_blank\">DataOutputStream dos = conn.openDataOutputStream();

232. dos.writeUTF(outputData); 233. dos.close();

234. } catch (java/io/IOException.java.html\"

target=\"_blank\">IOException e) { 235. }

236. } 237. }

小结

本文给出了一个简单的蓝牙服务的例子。旨在帮助开发者快速掌握JSR82.如果该文能对你有所启发,那就很好了。

参考资料

1. http://developers.sun.com/techtopics/mobility/apis/articles/bluetoothintro/

JSR82 API介绍(英文)

2. asp?ArticleID=249\">http://www.j2medev.com/Article/ShowArticle.asp?ArticleID=249

JSR82 API 介绍(中文)

3. http://www.jcp.org/en/jsr/detail?id=82 JSR82 Specification.

4.WTK22, BluetoothDemo 项目

作者简介

陈万飞,网名Jagie,培训师,爱好java技术.可通过chen_cwf@163.com与他联系

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- 517ttc.cn 版权所有 赣ICP备2024042791号-8

违法及侵权请联系:TEL:199 18 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务