蓝牙通信开发流程
为了让两个设备上的两个应用程序之间建立连接,你必须同时实现服务端和客户端机制。
- 服务端:使用的是 BluetoothServerSocket 类,并且调用的是 listenUsingRfcommWithServiceRecord(string,UUID) 方法来获得一个BluetoothServerSocket对象。
- 客户端:使用的是 BluetoothSocket 类,调用的是 createRfcommSocketToServiceRecord(UUID) 方法,这里的 UUID 会和服务端的UUID进行比较,如果匹配就能获得一个BluetoothSocket 对象。
- 公共端:在连接后,都会进入已连接线程。会在这个线程中进行写入和读取。
经典蓝牙连接相当于socket连接,是个非常耗时的操作,所以应该放到子线程中去完成。
服务端的监听线程:
// 创建监听线程,准备接受新连接。使用阻塞方式,调用BluetoothServerSocket.accept()
private class AcceptThread extends Thread {
private final BluetoothServerSocket mmServerSocket;
public AcceptThread(){
BluetoothServerSocket tmp = null;
try{
//MY_UUID用于唯一标识当前的蓝牙服务,在建立连接时会被客户端使用
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
}catch (IOException e){}
mmServerSocket = tmp;
}
public void run(){
BluetoothSocket socket= null;
while(mState != STATE_CONNECTED){
try{
// 保持监听状态,并阻塞线程,当连接建立时返回。
socket = mmServerSocket.accept();
}catch (IOException e) {
break;
}
if(socket != null){
//在单独的线程中对连接进行管理,本线程结束
ConnectedThread mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
try{
mmServerSocket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
}
public void cancel(){
try{
mmServerSocket.close();
}catch (IOException e){
e.printStackTrace();
}
}
}
客户端的连接线程:
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device){
Log.e("ChatTag", " -- ConnectThread -- ");
mmDevice=device;
BluetoothSocket tmp = null;
//获取一个 BluetoothSocket 以连接给定的 BluetoothDevice
try{
// MY_UUID 是应用程序的 UUID 字符串,也由服务器代码使用
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}catch (IOException e){
e.printStackTrace();
}
mmSocket = tmp;
}
public void run(){
// 取消发现,因为它会减慢连接速度
mAdapter.cancelDiscovery();
try{
// 请求连接,该操作会阻塞线程
// 直到成功或抛出异常
mmSocket.connect();
}catch (IOException e){
e.printStackTrace();
// Unable to connect; close the socket and get out
try{
mmSocket.close();
}catch (IOException e2){}
//ChatService.this.start();
return;
}
synchronized(ChatService.this){
mConnectedThread = null;
}
// 连接已建立,在单独的线程中对连接进行管理
ConnectedThread mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start();
}
public void cancel(){
/* try{
mmSocket.close();
}catch (IOException e){}*/
}
}
公共端的已连接线程:
// 双方蓝牙连接后一直运行的线程。构造函数中设置输入输出流
// Run方法中使用阻塞模式的Inputstream.read()循环读取输入流
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private InputStream mmInStream;
private OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket){
Log.e("ChatTag", " -- ConnectedThread -- ");
mmSocket = socket;
// 使用临时对象获取输入和输出流
try{
mmInStream = mmSocket.getInputStream();
mmOutStream = mmSocket.getOutputStream();
}catch (IOException e){}
}
public void run(){
byte[]buffer=new byte[1024];
int bytes;
//读数据需要不断监听 ,写 不需要
while (true) {
try {
//读取 InputStream 的数据
bytes = mmInStream.read(buffer);
} catch (IOException e) {
e.printStackTrace();
break;
}
}
}
public void write(byte[]buffer){
try{
mmOutStream.write(buffer);
}catch (IOException e){
e.printStackTrace();
}
}
public void cancel(){
try{
mmSocket.close();
}catch (IOException e){}
}
}
调用流程
-
在 主视图 的 onResume () 方法中,调用监听线程,等着被连接。
-
在蓝牙配对的流程中,在配对后会将配对的蓝牙设备地址 放入 Intent;
-
在 主视图 的 onActivityResult () 方法中,能从 Intent 中获取蓝牙设备地址
// 获取 蓝牙适配器 BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); // 通过蓝牙设备地址,获取 蓝牙设备 BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); // 然后调用连接线程,进行连接 ConnectThread mConnectThread = new ConnectThread(device); mConnectThread.start();
-
然后调用连接线程,请求连接服务端
-
当连接通过后,客户端和服务端就可以进行通信了。