目前,很多手机已经具备了蓝牙功能。虽然MIDP2.0没有包括蓝牙API,但是JCP定义了JSR82, Java APIs for Bluetooth Wireless Technology (JABWT).这是一个可选API,很多支持MIDP2.0的手机已经实现了,比如Nokia 6600, Nokia 6670,Nokia7610等等。对于一个开发者来说,如果目标平台支持JSR82的话,在制作联网对战类型游戏或者应用的时候,蓝牙是一个相当不错的选择。
本文给出了一个最简单的蓝牙应用的J2ME程序,用以帮助开发者快速的掌握JSR82。该程序分别在2台蓝牙设备上安装后,一台设备作为服务端先运行,一台设备作为客户端后运行。在服务端上我们发布了一个服务,该服务的功能是把客户端发过来的字符串转变为大写字符串。客户端起动并搜索到服务端的服务后,我们就可以从客户端的输入框里输入任意的字符串,发送到服务端去,同时观察服务端的反馈结果。
实例代码
该程序包括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];