蓝牙通信的大概步骤如下:
1,首先开启蓝牙
2,搜索可用设备
3,创建蓝牙socket,获取输入输出流
4,读取和写入数据
5,断开连接关闭蓝牙
首先要知道几个类,BluetoothAdapter,BluetoothGatt,BluetoothDevice,BluetoothCattService,BluetoothCattCharacteristic。
第一个是蓝牙设配器,对蓝牙的操作都需要用到它,很重要,BluetoothGatt作为中央来使用和处理数据,使用时有一个回调方法BluetoothGattCallback返回中央的状态和周边提供的数据,BluetoothCattService作为周边来提供数据;BluetoothGattServerCallback返回周边的状态。BluetoothDevice是蓝牙设备,BluetoothCattCharacteristic是蓝牙设备的特征。
看着有点乱,我们来打个比喻:BluetoothDevice为学校,BluetoothGatt为学校到达某一个班级的通道,BluetoothCattService为学校的某一个班级,BluetoothCattCharacteristic为班级中的某一个学生。那么蓝牙连接通信的过程就是这样,BluetoothAdapter先找到学校(就是连接目的设备),再通过通道找到目标班级,最后从班级中找到目标学生,这个学生就是我们设备之间通信的中介,很重要,学校有唯一的MAC地址,班级有唯一的serviceUUID,学生有唯一的charactersticUUID(相当于学号),所以就是在一所学校找一个学生的问题,好了,应该了解了吧。
蓝牙通信原理介绍:
蓝牙通信和socket通信原理基本上是一致的,下面我给大家上一张图(图为Socket通信图)。
蓝牙客户端Socket的与Sokcet流程是一样的,只不过参数不同而已。如下:
1、创建客户端蓝牙Sokcet
2、创建连接
3、读写数据
4、关闭
服务端socket:
1、创建服务端蓝牙Socket
2、绑定端口号(蓝牙忽略)
3、创建监听listen(蓝牙忽略, 蓝牙没有此监听,而是通过whlie(true)死循环来一直监听的)
4、通过accept(),如果有客户端连接,会创建一个新的Socket,体现出并发性,可以同时与多个socket通讯)
5、读写数据
6、关闭
下面看客户端代码:
/**
*Title: ConnectThread
*Description: 客户端逻辑: 客户端的线程,处理客户端socket
*Company: ihaveu
@authorMaWei * @date2017/12/26 */
public classConnectThreadextendsThread{
private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
/** 客户端socket*/
private final BluetoothSocket mmSoket;
/** 要连接的设备*/
private final BluetoothDevice mmDevice;
private BluetoothAdapter mBluetoothAdapter;
/** 主线程通信的Handler*/
private final Handler mHandler;
/** 发送和接收数据的处理类*/
private ConnectedThread mConnectedThread;
public ConnectThread(BluetoothDevice device, BluetoothAdapter bluetoothAdapter, Handler mUIhandler) {
mmDevice = device;
mBluetoothAdapter = bluetoothAdapter;
mHandler = mUIhandler;
BluetoothSocket tmp = null;
try {
// 创建客户端Socket
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
e.printStackTrace();
}
mmSoket = tmp;
}
@Override public void run() {
super.run();
// 关闭正在发现设备.(如果此时又在查找设备,又在发送数据,会有冲突,影响传输效率)
mBluetoothAdapter.cancelDiscovery();
try {
// 连接服务器
mmSoket.connect();
} catch (IOException e) {
// 连接异常就关闭
try {
mmSoket.close();
} catch (IOException e1) {
}
return;
}
manageConnectedSocket(mmSoket);
}
private void manageConnectedSocket(BluetoothSocket mmSoket) {
// 通知主线程连接上了服务端socket,更新UI
mHandler.sendEmptyMessage(Constant.MSG_CONNECTED_TO_SERVER);
// 新建一个线程进行通讯,不然会发现线程堵塞
mConnectedThread = new ConnectedThread(mmSoket,mHandler);
mConnectedThread.start();
}
/**
* 关闭当前客户端
*/ public void cancle() {
try {
mmSoket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/** * 发送数据 * @paramdata */
public void sendData(byte[] data) {
if(mConnectedThread != null) {
mConnectedThread.write(data);
}
}
}
服务端代码:
/** *
Title: AccepThread
*
Description: 服务端Socket通过accept()一直监听客户端连接的线程
*
Company: ihaveu
* * @authorMaWei * @date2017/12/26 */
public classAccepThreadextendsThread{
/** 连接的名称*/
private static final String NAME = "BluetoothClass";
/** UUID*/
private static final UUID MY_UUID = UUID.fromString(Constant.CONNECTTION_UUID);
/** 服务端蓝牙Sokcet*/
private final BluetoothServerSocket mmServerSocket;
private final BluetoothAdapter mBluetoothAdapter;
/** 线程中通信的更新UI的Handler*/
private final Handler mHandler;
/** 监听到有客户端连接,新建一个线程单独处理,不然在此线程中会堵塞*/
private ConnectedThread mConnectedThread;
public AccepThread(BluetoothAdapter adapter, Handler handler) throws IOException {
mBluetoothAdapter = adapter;
this.mHandler = handler;
// 获取服务端蓝牙socket
mmServerSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
}
@Override public void run() {
super.run();
// 连接的客户端soacket
BluetoothSocket socket = null;
// 服务端是不退出的,要一直监听连接进来的客户端,所以是死循环
while (true){
// 通知主线程更新UI,客户端开始监听
mHandler.sendEmptyMessage(Constant.MSG_START_LISTENING);
try {
// 获取连接的客户端socket
socket = mmServerSocket.accept();
} catch (IOException e) {
// 通知主线程更新UI, 获取异常
mHandler.sendEmptyMessage(Constant.MSG_ERROR);
e.printStackTrace();
// 服务端退出一直监听线程
break;
}
if(socket != null) {
// 管理连接的客户端socket
manageConnectSocket(socket);
// 这里应该是手动断开,案例应该是只保证连接一个客户端,所以连接完以后,关闭了服务端socket
try {
// mmServerSocket.close();
// mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
// } catch (IOException e) {
// e.printStackTrace();// } }
}
}
/** * 管理连接的客户端socket
* @paramsocket */
private void manageConnectSocket(BluetoothSocket socket) {
// 只支持同时处理一个连接
// mConnectedThread不为空,踢掉之前的客户端
if(mConnectedThread != null) {
mConnectedThread.cancle();
}
// 主线程更新UI,连接到了一个客户端
mHandler.sendEmptyMessage(Constant.MSG_GOT_A_CLINET);
// 新建一个线程,处理客户端发来的数据
mConnectedThread = new ConnectedThread(socket, mHandler);
mConnectedThread.start();
}
/**
* 断开服务端,结束监听
*/ public void cancle() {
try {
mmServerSocket.close();
mHandler.sendEmptyMessage(Constant.MSG_FINISH_LISTENING);
} catch (IOException e) {
e.printStackTrace();
}
}
/** * 发送数据
* @paramdata */
public void sendData(byte[] data){
if(mConnectedThread != null) {
mConnectedThread.write(data);
}
}
}
下面看一个共同通讯处理类:
/** *
Title: ConnectedThread
*Description: 客户端和服务端 处理 发送数据 和获取数据
*/
publicclassConnectedThreadextendsThread{
/** 当前连接的客户端BluetoothSocket*/
privatefinalBluetoothSocket mmSokcet;
/** 读取数据流*/
privatefinalInputStream mmInputStream;
/** 发送数据流*/
privatefinalOutputStream mmOutputStream;
/** 与主线程通信Handler*/
privateHandler mHandler;
privateString TAG ="ConnectedThread";
publicConnectedThread(BluetoothSocket socket,Handler handler) {
mmSokcet = socket; mHandler = handler;
InputStream tmpIn =null;
OutputStream tmpOut =null;
try{
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
}catch(IOException e) {
e.printStackTrace();
}
mmInputStream = tmpIn;
mmOutputStream = tmpOut;
}
@Overridepublicvoidrun() {
super.run();
byte[] buffer =newbyte[1024];
while(true) {
try{
// 读取数据
intbytes = mmInputStream.read(buffer);
if(bytes >0) {
String data =newString(buffer,0,bytes,"utf-8");
// 把数据发送到主线程, 此处还可以用广播
Message message = mHandler.obtainMessage(Constant.MSG_GOT_DATA,data);
mHandler.sendMessage(message);
}
Log.d(TAG,"messge size :"+ bytes);
}catch(IOException e)
{ e.printStackTrace();
}
}
}
// 踢掉当前客户端
publicvoidcancle() {
try{
mmSokcet.close();
}catch(IOException e) {
e.printStackTrace();
}
}
/** * 服务端发送数据 *
@paramdata */
publicvoidwrite(byte[] data) {
try{
mmOutputStream.write(data);
}catch(IOException e) {
e.printStackTrace();
}
}
}