服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

j2me蓝牙程序开发实战入门

  概述

  目前,很多手机已经具备了蓝牙功能。虽然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 {