概述
目前,很多手机已经具备了蓝牙功能。虽然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
- 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;
- /**
- * @author jagie
- *
- * midlet
- */
- public class stupidbtmidlet extends midlet implements commandlistener {
- list list;
- serverbox sb;
- clientbox cb;
- /*
- * (non-javadoc)
- *
- * @see javax.microedition.midlet.midlet#startapp()
- */
- protected void startapp() throws midletstatechangeexception {
- list = new list("傻瓜蓝牙入门", list.implicit);
- list.append("client", null);
- list.append("server", null);
- list.setcommandlistener(this);
- display.getdisplay(this).setcurrent(list);
- }
- /**
- * debug方法
- * @param s 要显示的字串
- */
- public void showstring(string s) {
- displayable dp = display.getdisplay(this).getcurrent();
- alert al = new alert(null, s, null, alerttype.info);
- al.settimeout(2000);
- display.getdisplay(this).setcurrent(al, dp);
- }
- /**
- * 显示主菜单
- *
- */
- public void showmainmenu() {
- display.getdisplay(this).setcurrent(list);
- }
- protected void pauseapp() {
- // todo auto-generated method stub
- }
- public void commandaction(command com, displayable disp) {
- if (com == list.select_command) {
- list list = (list) disp;
- int index = list.getselectedindex();
- if (index == 1) {
- if (sb == null) {
- sb = new serverbox(this);
- }
- sb.setstring(null);
- display.getdisplay(this).setcurrent(sb);
- } else {
- //每次都生成新的客户端实例
- cb = null;
- system.gc();
- cb = new clientbox(this);
- display.getdisplay(this).setcurrent(cb);
- }
- }
- }
- protected void destroyapp(boolean arg0) throws midletstatechangeexception {
- // todo auto-generated method stub
- }
- }
clientbox.java
- import java.io.datainputstream;
- import java.io.dataoutputstream;
- import java.io.ioexception;
- import java.util.vector;
- 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;
- import javax.microedition.lcdui.form;
- import javax.microedition.lcdui.gauge;
- import javax.microedition.lcdui.stringitem;
- import javax.microedition.lcdui.textfield;
- //jsr082 api
- import javax.bluetooth.bluetoothstateexception;
- import javax.bluetooth.deviceclass;
- import javax.bluetooth.discoveryagent;
- import javax.bluetooth.discoverylistener;
- import javax.bluetooth.localdevice;
- import javax.bluetooth.remotedevice;
- import javax.bluetooth.servicerecord;
- import javax.bluetooth.uuid;
- /**
- * 客户端gui
- * @author jagie
- *
- * todo to change the template for this generated type comment go to
- * window - preferences - java - code style - code templates
- */
- public class clientbox extends form implements runnable, commandlistener,
- discoverylistener {
- //字串输入框
- textfield input = new textfield(null, "", 50, textfield.any);
- //loger
- stringitem result = new stringitem("结果:", "");
- private discoveryagent discoveryagent;
- private uuid[] uuidset;
- //响应服务的uuid
- private static final uuid echo_server_uuid = new uuid(
- "f0e0d0c0b0a000908070605040302010", false);
- //设备集合
- vector devices = new vector();
- //服务集合
- vector records = new vector();
- //服务搜索的事务id集合
- int[] transids;
- stupidbtmidlet midlet;
- public clientbox(stupidbtmidlet midlet) {
- super("");
- this.midlet=midlet;
- this.append(result);
- this.addcommand(new command("取消",command.cancel,1));
- this.setcommandlistener(this);
- new thread(this).start();
- }
- public void commandaction(command arg0, displayable arg1) {
- if(arg0.getcommandtype()==command.cancel){
- midlet.showmainmenu();
- }else{
- //匿名内部thread,访问远程服务。
- thread fetchthread=new thread(){
- public void run(){
- for(int i=0;i<records.size();i++){
- servicerecord sr=(servicerecord)records.elementat(i);
- if(accessservice(sr)){
- //访问到一个可用的服务即可
- break;
- }
- }
- }
- };
- fetchthread.start();
- }
- }
- private boolean accessservice(servicerecord sr){
- boolean result=false;
- try {
- string url = sr.getconnectionurl(
- servicerecord.noauthenticate_noencrypt, false);
- streamconnection conn = (streamconnection) connector.open(url);
- dataoutputstream dos=conn.opendataoutputstream();
- dos.writeutf(input.getstring());
- dos.close();
- datainputstream dis=conn.opendatainputstream();
- string echo=dis.readutf();
- dis.close();
- showinfo("反馈结果是:"+echo);
- result=true;
- } catch (ioexception e) {
- }
- return result;
- }
- public synchronized void run() {
- //发现设备和服务的过程中,给用户以gauge
- gauge g=new gauge(null,false,gauge.indefinite,gauge.continuous_running);
- this.append(g);
- showinfo("蓝牙初始化...");
- boolean isbtready = false;
- try {
- localdevice localdevice = localdevice.getlocaldevice();
- discoveryagent = localdevice.getdiscoveryagent();
- isbtready = true;
- } catch (exception e) {
- e.printstacktrace();
- }
- if (!isbtready) {
- showinfo("蓝牙不可用");
- //删除gauge
- this.delete(1);
- return;
- }
- uuidset = new uuid[2];
- //标志我们的响应服务的uuid集合
- uuidset[0] = new uuid(0x1101);
- uuidset[1] = echo_server_uuid;
- try {
- discoveryagent.startinquiry(discoveryagent.giac, this);
- } catch (bluetoothstateexception e) {
- }
- try {
- //阻塞,由inquirycompleted()回调方法唤醒
- wait();
- } catch (interruptedexception e1) {
- e1.printstacktrace();
- }
- showinfo("设备搜索完毕,共找到"+devices.size()+"个设备,开始搜索服务");
- transids = new int[devices.size()];
- for (int i = 0; i < devices.size(); i++) {
- remotedevice rd = (remotedevice) devices.elementat(i);
- try {
- //记录每一次服务搜索的事务id
- transids[i] = discoveryagent.searchservices(null, uuidset,
- rd, this);
- } catch (bluetoothstateexception e) {
- continue;
- }
- }
- try {
- //阻塞,由servicesearchcompleted()回调方法在所有设备都搜索完的情况下唤醒
- wait();
- } catch (interruptedexception e1) {
- e1.printstacktrace();
- }
- showinfo("服务搜索完毕,共找到"+records.size()+"个服务,准备发送请求");
- if(records.size()>0){
- this.append(input);
- this.addcommand(new command("发送",command.ok,0));
- }
- //删除gauge
- this.delete(1);
- }
- /**
- * debug
- * @param s
- */
- private void showinfo(string s){
- stringbuffer sb=new stringbuffer(result.gettext());
- if(sb.length()>0){
- sb.append("/n");
- }
- sb.append(s);
- result.settext(sb.tostring());
- }
- /**
- * 回调方法
- */
- public void devicediscovered(remotedevice btdevice, deviceclass cod) {
- if (devices.indexof(btdevice) == -1) {
- devices.addelement(btdevice);
- }
- }
- /**
- * 回调方法,唤醒初始化线程
- */
- public void inquirycompleted(int disctype) {
- synchronized (this) {
- notify();
- }
- }
- /**
- * 回调方法
- */
- public void servicesdiscovered(int transid, servicerecord[] servrecord) {
- for (int i = 0; i < servrecord.length; i++) {
- records.addelement(servrecord[i]);
- }
- }
- /**
- * 回调方法,唤醒初始化线程
- */
- public void servicesearchcompleted(int transid, int respcode) {
- for (int i = 0; i < transids.length; i++) {
- if (transids[i] == transid) {
- transids[i] = -1;
- break;
- }
- }
- //如果所有的设备都已经搜索服务完毕,则唤醒初始化线程。
- boolean finished = true;
- for (int i = 0; i < transids.length; i++) {
- if (transids[i] != -1) {
- finished = false;
- break;
- }
- }
- if (finished) {
- synchronized (this) {
- notify();
- }
- }
- }
- }
serverbox.java
- import java.io.datainputstream;
- import java.io.dataoutputstream;
- import java.io.ioexception;
- import java.util.vector;
- import javax.bluetooth.discoveryagent;
- import javax.bluetooth.localdevice;
- import javax.bluetooth.servicerecord;
- import javax.bluetooth.uuid;
- import javax.microedition.io.connector;
- import javax.microedition.io.streamconnection;
- import javax.microedition.io.streamconnectionnotifier;
- import javax.microedition.lcdui.command;
- import javax.microedition.lcdui.commandlistener;
- import javax.microedition.lcdui.displayable;
- import javax.microedition.lcdui.textbox;
- import javax.microedition.lcdui.textfield;
- /**
- * 服务端gui
- * @author jagie
- *
- * todo to change the template for this generated type comment go to
- * window - preferences - java - code style - code templates
- */
- public class serverbox extends textbox implements runnable, commandlistener {
- command com_pub = new command("开启服务", command.ok, 0);
- command com_cancel = new command("终止服务", command.cancel, 0);
- command com_back = new command("返回", command.back, 1);
- localdevice localdevice;
- streamconnectionnotifier notifier;
- servicerecord record;
- boolean isclosed;
- clientprocessor processor;
- stupidbtmidlet midlet;
- //响应服务的uuid
- private static final uuid echo_server_uuid = new uuid(
- "f0e0d0c0b0a000908070605040302010", false);
- public serverbox(stupidbtmidlet midlet) {
- super(null, "", 500, textfield.any);
- this.midlet = midlet;
- this.addcommand(com_pub);
- this.addcommand(com_back);
- this.setcommandlistener(this);
- }
- public void run() {
- boolean isbtready = false;
- try {
- localdevice = localdevice.getlocaldevice();
- if (!localdevice.setdiscoverable(discoveryagent.giac)) {
- showinfo("无法设置设备发现模式");
- return;
- }
- // prepare a url to create a notifier
- stringbuffer url = new stringbuffer("btspp://");
- // indicate this is a server
- url.append("localhost").append(':');
- // add the uuid to identify this service
- url.append(echo_server_uuid.tostring());
- // add the name for our service
- url.append(";name=echo server");
- // request all of the client not to be authorized
- // some devices fail on authorize=true
- url.append(";authorize=false");
- // create notifier now
- notifier = (streamconnectionnotifier) connector
- .open(url.tostring());
- record = localdevice.getrecord(notifier);
- // remember we've reached this point.
- isbtready = true;
- } catch (exception e) {
- e.printstacktrace();
- }
- // nothing to do if no bluetooth available
- if (isbtready) {
- showinfo("初始化成功,等待连接");
- this.removecommand(com_pub);
- this.addcommand(com_cancel);
- } else {
闽公网安备 35060202000074号