WEB开发网
开发学院WEB开发Jsp J2ME蓝牙程序开发实战入门 阅读

J2ME蓝牙程序开发实战入门

 2008-01-05 20:35:06 来源:WEB开发网   
核心提示:概述目前,很多手机已经具备了蓝牙功能,J2ME蓝牙程序开发实战入门,虽然MIDP2.0没有包括蓝牙API,但是JCP定义了JSR82, java APIs for Bluetooth Wireless Technology (JABWT).这是一个可选API,很多支持MIDP2.0的手机已经实现了,比如Nokia 66
  概述 目前,很多手机已经具备了蓝牙功能。虽然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. import javax.microedition.lcdui.Alert;
  2. import javax.microedition.lcdui.AlertType;
  3. import javax.microedition.lcdui.Command;
  4. import javax.microedition.lcdui.CommandListener;
  5. import javax.microedition.lcdui.Display;
  6. import javax.microedition.lcdui.Displayable;
  7. import javax.microedition.lcdui.List;
  8. import javax.microedition.midlet.MIDlet;
  9. import javax.microedition.midlet.MIDletStateChangeException;
  10. /**
  11.  * @author Jagie
  12.  * 
  13.  * MIDlet
  14.  */
  15. public class StupidBTMIDlet extends MIDlet implements CommandListener {
  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 MIDletStateChangeException {
  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(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 disp) {
  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);
  64.       } else {
  65.         //每次都生成新的客户端实例
  66.         cb = null;
  67.         System.gc();
  68.         cb = new ClientBox(this);
  69.         Display.getDisplay(this).setCurrent(cb);
  70.       }
  71.     }
  72.   }
  73.   protected void destroyApp(boolean arg0) throws MIDletStateChangeException {
  74.     // TODO Auto-generated method stub
  75.   }
  76. }

  ClientBox.java

  1. import java.io.DataInputStream;
  2. import java.io.DataOutputStream;
  3. import java.io.IOException;
  4. import java.util.Vector;
  5. import javax.microedition.io.Connector;
  6. import javax.microedition.io.StreamConnection;
  7. import javax.microedition.lcdui.Command;
  8. import javax.microedition.lcdui.CommandListener;
  9. 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 comment go to
  28.  * Window - Preferences - Java - Code Style - Code Templates
  29.  */
  30. public class ClientBox extends Form implements 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 UUID(
  42.       "F0E0D0C0B0A000908070605040302010", false);
  43.   //设备集合
  44.   Vector devices = new Vector();
  45.   //服务集合
  46.   Vector records = new 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 Thread(this).start();
  61.   }
  62.   
  63.   public void commandAction(Command arg0, Displayable arg1) {
  64.     if(arg0.getCommandType()==Command.CANCEL){
  65.       midlet.showMainMenu();
  66.     }else{
  67.       //匿名内部Thread,访问远程服务。
  68.       Thread fetchThread=new Thread(){
  69.         public void run(){
  70.           for(int i=0;i<records.size();i++){
  71.             ServiceRecord sr=(ServiceRecord)records.elementAt(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.       String url = sr.getConnectionURL(
  89.           ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
  90.       StreamConnection  conn = (StreamConnection) Connector.open(url);
  91.       
  92.       DataOutputStream dos=conn.openDataOutputStream();
  93.       dos.writeUTF(input.getString());
  94.       dos.close();
  95.       DataInputStream dis=conn.openDataInputStream();
  96.       String echo=dis.readUTF();
  97.       dis.close();
  98.       showInfo("反馈结果是:"+echo);
  99.       result=true;
  100.       
  101.     } catch (IOException e) {
  102.       
  103.     }
  104.     return result;
  105.   }
  106.   public synchronized void run() {
  107.     //发现设备和服务的过程中,给用户以Gauge
  108.     Gauge g=new Gauge(null,false,Gauge.INDEFINITE,Gauge.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 (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, this);
  132.     } catch (BluetoothStateException e) {
  133.     }
  134.     try {
  135.       //阻塞,由inquiryCompleted()回调方法唤醒
  136.       wait();
  137.     } catch (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.elementAt(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 (InterruptedException e1) {
  158.       e1.printStackTrace();
  159.     }
  160.     
  161.     showInfo("服务搜索完毕,共找到"+records.size()+"个服务,预备发送请求");
  162.     if(records.size()>0){
  163.       this.append(input);
  164.       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(String s){
  178.     StringBuffer sb=new 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.    */
  189.   public void deviceDiscovered(RemoteDevice btDevice, DeviceClass 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 respCode) {
  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.DataInputStream;
  2. import java.io.DataOutputStream;
  3. import java.io.IOException;
  4. import java.util.Vector;
  5. import javax.bluetooth.DiscoveryAgent;
  6. import javax.bluetooth.LocalDevice;
  7. import javax.bluetooth.ServiceRecord;
  8. import javax.bluetooth.UUID;
  9. 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 comment go to
  22.  * Window - Preferences - Java - Code Style - Code Templates
  23.  */
  24. public class ServerBox extends TextBox implements 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 UUID(
  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.       StringBuffer url = new 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
  64.       notifier = (StreamConnectionNotifier) Connector
  65.           .open(url.toString());
  66.       record = localDevice.getRecord(notifier);
  67.       // remember we've reached this point.
  68.       isBTReady = true;
  69.     } catch (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 {

Tags:JME 蓝牙 程序开发

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接