package BTClient;
//这是别人的代码 具体在那拷贝的 我忘记了,这不是我的原创,只是我学习半个月 才搞懂的 发上来 大家可以参考一下
//对象主要调用两个方法 搜索 发送
import java.io.*;
import java.util.*;
import javax.bluetooth.*;
import javax.bluetooth.UUID;
import javax.microedition.io.*;
////////////////////////////////////////////////////////////////////////////////////////////////////
public class BTClient implements DiscoveryListener, Runnable {
//接口 DiscoveryListener
public static final String uuidString = "0123456789ABCDEF0123456789ABCDEF";
public static UUID uuid;
private LocalDevice localDevice;// 本地设备实例
String localBTAddress;// 本地蓝牙地址
String localBTName;// 蓝牙名称
DiscoveryAgent discoveryAgent;// 发现代理
Thread th;
Thread readWorkTh;
Thread writeWorkTh;
StreamConnection conn;
boolean exitFlag;
boolean BTReady;//状态标记
DataInputStream in;
DataOutputStream out;
String sendText = "";
Hashtable remoteDevices = new Hashtable();// 存储找到的远程设备 哈什表java.util.Hashtable
String url = null;
ServiceRecord serviceRecord;
////////////////////////////////////////////////////////////////////////////////////////////////////
public BTClient() {
th = new Thread(this);
th.start();
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void run() {
if (!initBT()) {
return; //返回
}
try {
// 等待启动服务搜索,看清下面的search()搜索这里先暂停它
synchronized (this) {
//代码块中的代码必须获得对象 syncObject (如前所述,可以是类实例或类)的锁才能执行!
try {
wait();//会释放这个锁,让其它线程有机会运行。
} catch (InterruptedException e) {
e.printStackTrace();
}
}////
if (exitFlag)
return;//返回
search();
///////////////////////////// /////////////////////////////
// 等待URL准备好
synchronized (this) { //等到被唤醒后 再继续运行
try {
wait();//会释放这个锁,让其它线程有机会运行。
} catch (InterruptedException e) {
e.printStackTrace();
}
}////
if (exitFlag)
return;//返回
conn = (StreamConnection) Connector.open(url);
in = conn.openDataInputStream();
out = conn.openDataOutputStream();
readWorkTh = new ReadWorkThread();
readWorkTh.start();
writeWorkTh = new WriteWorkThread();
writeWorkTh.start();
BTReady = true;
} catch (IOException e) {
return;//返回
} catch (SecurityException e) {
return;//返回
}
th = null;//Thread为空
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public boolean initBT() { //初始化蓝牙-文文风 这很简单 初始化就可以了主要是地址!
boolean success = false;
try {
uuid = new UUID(uuidString, false);// 我们的UUID
// 取得本地设备实例
localDevice = LocalDevice.getLocalDevice();
// 记录蓝牙地址
localBTAddress = localDevice.getBluetoothAddress();
// 记录蓝牙名称
localBTName = localDevice.getFriendlyName();
localDevice.setDiscoverable(DiscoveryAgent.GIAC);
// 取得蓝牙代理
discoveryAgent = localDevice.getDiscoveryAgent();
success = true;
} catch (Exception e) {
System.err.println("初始化蓝牙设备失败:" + e);
}
return success;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void search() {// 搜索设备,搜索服务
try { //remoteDevices哈什表
// 清除remoteDevices
remoteDevices.clear();
// 将缓存的和已知的蓝牙设备加入cacheDevices++preDevices==remoteDevices
RemoteDevice[] cacheDevices = discoveryAgent.retrieveDevices(DiscoveryAgent.CACHED);
// class RemoteDevice//缓存的
if (cacheDevices != null) {
for (int i = 0; i < cacheDevices.length; i++) {
remoteDevices.put(cacheDevices[i].getBluetoothAddress(), cacheDevices[i]);
//哈什表
}
}
RemoteDevice[] preDevices = discoveryAgent.retrieveDevices(DiscoveryAgent.PREKNOWN);
// class RemoteDevice//已知的
if (preDevices != null) {
for (int i = 0; i < preDevices.length; i++) {
remoteDevices.put(cacheDevices[i].getBluetoothAddress(),cacheDevices[i]);
//哈什表 这里好像写错了 应该是preDevices
}
}
// 在缓存的和已知的设备上查询“服务”,函数定义在下面
searchServices(remoteDevices);
if (serviceRecord != null)// 找到返回
return;
// 开始搜索设备
discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);//这里的this是指本类.当然我们要在本类实现DiscoveryListener接口.
// 在搜索到的设备上查询服务
searchServices(remoteDevices);//去下面看看这个函数的实现
remoteDevices.clear();
} catch (BluetoothStateException e) {
e.printStackTrace();
}
if (serviceRecord != null) {
notify(); //叫醒谁??应该是下一个 就是上面等待URL的那个块,运行到这里 数据已经获取了 可以连接了
} else {
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
private void searchServices(Hashtable remotes) throws BluetoothStateException //根据hash表查询设备
{// 搜索服务
// 创建我们感兴趣的UUID数组,我这里只搜索可以提供-蓝牙串口-的设备
UUID[] UUIDs = new UUID[1];
//UUIDs[1] = new UUID(uuidString, false);// 我们的UUID
UUIDs[0] = new UUID(0x0003);// 必须支持RFCOMM
// 取出每一个设备查询
for (Enumeration e = remotes.keys(); e.hasMoreElements();) {
String key = (String) e.nextElement(); //我们用到了哈什表 这里要转换为remotes类型
RemoteDevice remoteDevice = (RemoteDevice) remotes.get(key);
//看清楚了 这是remoteDevice 不是remoteDevices!!!!讨厌
// 查询服务-使用发现代理 到这里不用管它了 它会自动调用回调函数的 可以去休息了
discoveryAgent.searchServices(null, UUIDs, remoteDevice, this);
}//这是循环尾 到这里了
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void deviceDiscovered(RemoteDevice device, DeviceClass cod) { //如果搜索到了有新设备,它会调用deviceDiscoverd()方法接收!
// 记录找到的设备
remoteDevices.put(device.getBluetoothAddress(), device);
} //哈什表
//发现服务
////////////////////////////////////////////////////////////////////////////////////////////////////
public void servicesDiscovered(int transID, ServiceRecord[] servRecord) {
// 发现感兴趣的服务,这里直接使用第一个
if (servRecord == null || servRecord.length == 0) {
url = null;
serviceRecord = null;
return;
}
// 取得感兴趣的连接URL,这里直接使用第一个,其它的不要了,我用直接写入的。不要学我啊
//给大家看个例子 btspp://00195D0F4245:3;authenticate=false;encrypt=false;master=false
//把地址改一下就可以用了,用不了 自己看参数呀 通道数我的机器有 2 3 7 你的电脑也许不是这些
serviceRecord = servRecord[0]; //服务记录是个接口
url = serviceRecord.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void inquiryCompleted(int discType) { //设备查询完成
try {
searchServices(remoteDevices); //开始查询服务了,
} catch (BluetoothStateException e) {
e.printStackTrace();
}
remoteDevices.clear();//这里清空哈什表,释放资源,以后不用了,其实不用也是可以的。
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void serviceSearchCompleted(int transID, int respCode) {//服务查询完成
synchronized (this) { //同步
notifyAll();
//服务查询完成后 会叫醒所有线程。
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void close() {
try {
exitFlag = true;
synchronized (this) {
notify(); //这也有唤醒 但是不知道具体做什么用的?请教一下
}
if (writeWorkTh != null) {
synchronized (writeWorkTh) {
writeWorkTh.notify(); //这也有唤醒,请教!
}
}
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
if (conn != null)
conn.close();
if (readWorkTh != null) {
readWorkTh.join();
}
if (writeWorkTh != null)
writeWorkTh.join();
if (th != null)
th.join();
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void send(String str) { ////发送信息 外部对象会调用此方法
if (writeWorkTh == null)
return;
sendText = str;
synchronized (writeWorkTh) {
writeWorkTh.notify(); //指定线程唤醒 别睡了 干活了
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
class ReadWorkThread extends Thread {
public void run() {
try {
while (!exitFlag) {
String str = in.readUTF();
if (str != null) {
}
}
} catch (IOException e) {
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
class WriteWorkThread extends Thread {
public void run() {
try {
while (!exitFlag) {
synchronized (this) {////
try {
wait();//这等待一下
} catch (InterruptedException e) {
e.printStackTrace();
}
if (exitFlag)// 可能因为关闭操作被打断
break;
if (sendText != null)
out.writeUTF(sendText);
}////
}
} catch (IOException e) {
}
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
public void startSearch() { ////搜索 同样 外部对象会调用此方法
synchronized (this) {
notifyAll();//这里是全部唤醒
}
}
}
J2ME 蓝牙 串口 连接PC
最新推荐文章于 2021-05-26 05:11:23 发布