1利用系统中的自动重连
getDevice().connectGatt(context, autoConnect, coreGattCallback);
private BleGattCallback coreGattCallback = new BleGattCallback() { @Override public void onDisConnected(BluetoothGatt gatt, int status, BleException exception) { BleLog.i("BleGattCallback:onConnectFailure "); if(null != gatt && tryConnectCount > 0 && !isClosed){ tryConnectCount --; if(gatt.connect()) { onDisConnected2Reconnect(gatt, status, exception); return ; } } closeBluetoothGatt(); bluetoothGatt = null; Iterator iterator = callbackHashMap.entrySet().iterator(); while (iterator.hasNext()) { Map.Entry entry = (Map.Entry) iterator.next(); Object call = entry.getValue(); if (call instanceof BleGattCallback) { ((BleGattCallback) call).onDisConnected(gatt, status, exception); } } }
}
/** * Connect back to remote device. * * <p>This method is used to re-connect to a remote device after the * connection has been dropped. If the device is not in range, the * re-connection will be triggered once the device is back in range. * * @return true, if the connection attempt was initiated successfully */ public boolean connect() { try { mService.clientConnect(mClientIf, mDevice.getAddress(), false, mTransport); // autoConnect is inverse of "isDirect" return true; } catch (RemoteException e) { Log.e(TAG,"",e); return false; } }
2 另外自己控制重连,https://bbs.csdn.net/topics/391008501
public
class
BluetoothMain {
private
boolean
isConnected =
false
;
private
volatile
boolean
hasDataToSend =
false
;
private
volatile
boolean
hasDataToReceive =
false
;
private
boolean
isScaning =
false
;
private
boolean
isNeedConnect =
false
;
// 用在回调函数中,当连接状态断开后,判断是否是正常断开还是需要重连
private
HandlerThread handlerThread =
null
;
private
Handler handler =
null
;
private
Runnable runnable =
null
;
// XXX 关于定时器和计数器的时间计数设置需要重新设定
private
Counter dataTransferCounter =
null
;
private
Counter readCounter =
null
;
// this counter is to process read failed so many times
private
Counter writeAfterReadCounter =
null
;
// this counter is to process write failed so many times after successful read
private
Counter ackConfirmCounter =
null
;
// this counter is to prevent infinitely read characteristic after writing an ack
private
java.util.Timer timer =
null
;
// 主要用于连接失败时进行尝试
private
BluetoothManager bleManager =
null
;
private
BluetoothAdapter mAdapter =
null
;
private
BluetoothAdapter.LeScanCallback mLeScanCallback =
null
;
private
BluetoothGattCallback gattCallback =
null
;
private
BluetoothGatt bluetoothGatt =
null
;
private
Context context =
null
;
private
BLECallback bleCallback =
null
;
private
byte
bleRssi =
0
;
private
byte
scanCount =
0
;
private
byte
connectCount =
0
;
private
short
postTime =
0
;
private
static
final
boolean
DBG =
true
;
private
static
final
String BLUETOOTH_INFO =
"bluetoothComm"
;
public
BluetoothMain(Context context, List<String> deviceUUIDList, BLECallback bleCb) {
this
.context = context;
bleCallback = bleCb;
bleUUIDList = deviceUUIDList;
bleManager = (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
mAdapter = bleManager.getAdapter();
deviceFoundSet =
new
HashSet<String>();
deviceLoseMap =
new
ConcurrentHashMap<String, Boolean>();
deviceInControlSet =
new
HashSet<String>();
activeDevices =
new
HashSet<String>();
sleepDevices =
new
HashSet<String>();
dataSendUuidQueue =
new
HashMap<String, Queue<
byte
[]>>();
mLeScanCallback =
new
LeScanCallback() {
@Override
public
void
onLeScan(BluetoothDevice device,
int
rssi,
byte
[] scanRecord) {
bleRssi = (
byte
) rssi;
String bleAddress = device.getAddress();
String deviceUUID = FrameUtility.convertMACToUUID(bleAddress);
if
(scanRecord[
7
] == GattConstants.ADVERTISE_TYPE_SLEEP){
// 判断设备是否是处于休眠状态,然后更新设备所在的集合(活跃设备、休眠设备)
if
( activeDevices.contains(deviceUUID)){
activeDevices.remove(deviceUUID);
}
sleepDevices.add(deviceUUID);
}
else
{
if
( sleepDevices.contains(deviceUUID)){
sleepDevices.remove(deviceUUID);
}
activeDevices.add(deviceUUID);
// 小节点处于活跃状态
if
(scanRecord[
7
] == GattConstants.ADVERTISE_TYPE_COMMON) {
// 小节点没有数据发送,根据deviceUUID查看dataSendUUIDList中是否有数据需要发送
if
(dataSendUuidQueue.get(deviceUUID) !=
null
&& dataSendUuidQueue.get(deviceUUID).size() >
0
){
if
(firstScanToSend) {
firstScanToSend =
false
;
hasDataToSend =
true
;
connect(bleAddress);
}
}
}
else
if
(scanRecord[
7
] == GattConstants.ADVERTISE_TYPE_DATA) {
// 小节点有数据需要发送
if
(firstScanToReceive) {
firstScanToReceive =
false
;
connect(bleAddress);
}
}
}
}
};
gattCallback =
new
BluetoothGattCallback() {
@Override
public
void
onConnectionStateChange(BluetoothGatt gatt,
int
status,
int
newState) {
super
.onConnectionStateChange(gatt, status, newState);
if
(status == BluetoothGatt.GATT_SUCCESS){
if
(DBG){Log.d(BLUETOOTH_INFO,
"onConnectionStateChange ---> operation success"
);}
if
(newState == BluetoothGatt.STATE_DISCONNECTED) {
if
(!isConnected) {
if
(!isNeedConnect) {
// 正常断开
if
(DBG){Log.d(BLUETOOTH_INFO,
"onConnectionStateChange ---> disconnected"
);}
}
}
else
{
// 意外断开后直接断开,不尝试重连
if
(DBG){Log.d(BLUETOOTH_INFO,
"onConnectionStateChange ---> disconnected acidentally"
);}
isConnected =
false
;
firstScanToSend =
true
;
firstScanToReceive =
true
;
}
if
(bluetoothGatt !=
null
){
bluetoothGatt.close();
// 释放资源
bluetoothGatt =
null
;
}
//断开连接,开始扫描。经测试,不能直接调用startSearch(),否则会有10s的延时。
//另外,若立即开始扫描的话,由于蓝牙节点的广播切换需要时间,可能还会扫描到"02"广播包,导致不必要的连接。
handler.postDelayed(runnable,
400
);
}
else
if
(newState == BluetoothGatt.STATE_CONNECTED) {
isConnected =
true
;
isNeedConnect =
false
;
if
(timer !=
null
){
timer.cancel();
timer =
null
;
}
// 进行服务发现,50ms
try
{
Thread.sleep(
50
);
}
catch
(Exception e) {
e.printStackTrace();
}
gatt.discoverServices();
}
}
else
{
if
(DBG){Log.d(BLUETOOTH_INFO,
"onConnectionStateChange ---> operation failure"
);}
}
}
@Override
public
void
onServicesDiscovered(
final
BluetoothGatt gatt,
int
status) {
super
.onServicesDiscovered(gatt, status);
BluetoothGattService service = gatt.getService(UUID.fromString(GattConstants.SERVICE_UUID));
BluetoothGattCharacteristic readCharacteristic_2 = service.getCharacteristic(UUID.fromString(GattConstants.CHARACTERISTIC_READ_UUID_2));
gatt.readCharacteristic(readCharacteristic_2);
}
@Override
public
void
onCharacteristicRead(
final
BluetoothGatt gatt,
final
BluetoothGattCharacteristic characteristic,
int
status) {
super
.onCharacteristicRead(gatt, characteristic, status);
byte
[] data = characteristic.getValue();
BluetoothGattService service = gatt.getService(UUID.fromString(GattConstants.SERVICE_UUID));
BluetoothGattCharacteristic writeCharacteristic_1 = service.getCharacteristic(UUID.fromString(GattConstants.CHARACTERISTIC_WRITE_UUID_1));
final
String deviceUuid = FrameUtility.convertMACToUUID(gatt.getDevice().getAddress());
// 手机向小节点发送数据是通过写特征值1来实现的,当小节点读取完数据之后,将特征值设为全1
if
(characteristic.equals(writeCharacteristic_1)) {
// 读特征值1操作成功
if
(status == BluetoothGatt.GATT_SUCCESS) {
// 小节点读取完毕,关闭超时计数器,继续发送下一个数据
if
(isArrayEqual(data, GattConstants.FrameInfo.ALL_ONE_RSP.getBytes())) {
if
(readCounter !=
null
) {
readCounter.close();
readCounter =
null
;
}
dataSendUuidQueue.get(deviceUuid).poll();
sendNextPacket();
}
else
{
// 小节点未将数据取走,计数器加1
if
(readCounter ==
null
) {
// 连续读取10次失败之后,断开连接,回到初始状态
readCounter =
new
Counter(
10
,
"readCounter"
,
new
CounterTask() {
@Override
public
void
run() {
readCounter.close();
readCounter =
null
;
// sendNextPacket();
dataSendUuidQueue.get(deviceUuid).poll();
//由于PC和服务器端存在重传机制,超时之后删除当前数据包,并断开连接
disconnect();
}
});
readCounter.start();
}
readCounter.addCount();
if
(readCounter.getCount() <= readCounter.getMaxCount()) {
gatt.readCharacteristic(characteristic);
}
}
}
else
{
// CQ:实验中测试,程序到达这里之后,连接会断开然后自动重新连接
if
(DBG){Log.d(BLUETOOTH_INFO,
"onCharacteristicRead status---> failed"
);}
}
}
else
{
// 读特征值2(用于小节点向手机发送数据)
if
(status == BluetoothGatt.GATT_SUCCESS) {
// 如果读到的数据为全0,表示小节点没有数据要发送
if
(isArrayEqual(data, GattConstants.FrameInfo.ALL_ZERO_RSP.getBytes())) {
// XXX 不使用计数器,若没有数据则直接断开
if
(ackConfirmCounter !=
null
) {
ackConfirmCounter.close();
ackConfirmCounter =
null
;
}
hasDataToReceive =
false
;
if
(hasDataToSend) {
sendNextPacket();
}
else
{
// 手机没有数据要发送
disconnect();
}
}
else
if
(isArrayEqual(data, GattConstants.FrameInfo.ALL_ONE_RSP.getBytes())) {
hasDataToReceive =
false
;
if
(hasDataToSend) {
sendNextPacket();
}
else
{
// 手机没有数据要发送
if
(DBG){Log.d(BLUETOOTH_INFO,
"disconnect ---> no data to send"
);}
disconnect();
}
}
else
{
// 小节点有数据发送过来
if
(ackConfirmCounter !=
null
) {
ackConfirmCounter.close();
ackConfirmCounter =
null
;
}
hasDataToReceive =
true
;
if
(data[GattConstants.FrameInfo.FRAME_HEX_MAX_LEN] ==
'1'
) {
// 最后一个字节为'1',表示小节点还有数据需要发送
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
characteristic.setValue(GattConstants.FrameInfo.ALL_ONE_RSP.getBytes());
gatt.writeCharacteristic(characteristic);
}
else
if
(data[GattConstants.FrameInfo.FRAME_HEX_MAX_LEN] ==
'0'
) {
// 最后一个字节为'0',表示小节点没有数据需要发送
hasDataToReceive =
false
;
// CQ:读完最后一个数据包之后,将特征值全部置0,表示这一个阶段结束
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
characteristic.setValue(GattConstants.FrameInfo.ALL_ZERO_RSP.getBytes());
gatt.writeCharacteristic(characteristic);
}
// 对读取到的数据包进行转义,然后调用回调接口向上层发送数据
String uuid = FrameUtility.convertMACToUUID(bluetoothGatt.getDevice().getAddress());
byte
[] dataToServer = FrameUtility.decodeFrame(data,
true
, uuid.getBytes(),(
byte
)-bleRssi);
//printData(dataToServer, "data to server");
bleCallback.dataReceivedCb(dataToServer);
}
}
}
}
|
@Override
public
void
onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic,
int
status) {
super
.onCharacteristicWrite(gatt, characteristic, status);
byte
[] data = characteristic.getValue();
printData(data,
"onCharacteristicWrite"
);
BluetoothGattService service = gatt.getService(UUID.fromString(GattConstants.SERVICE_UUID));
BluetoothGattCharacteristic writeCharacteristic_1 = service.getCharacteristic(UUID.fromString(GattConstants.CHARACTERISTIC_WRITE_UUID_1));
if
(characteristic.equals(writeCharacteristic_1)) {
// CQ:手机利用特征值1向小节点发送数据
if
(status == BluetoothGatt.GATT_SUCCESS) {
// CQ:写操作成功,关闭并清空超时计数器
if
(dataTransferCounter !=
null
) {
dataTransferCounter.close();
dataTransferCounter =
null
;
}
// 等待100ms,读取特征值,看小节点是否读取完毕
try
{
Thread.sleep(
100
);
}
catch
(Exception e) {
e.printStackTrace();
}
gatt.readCharacteristic(characteristic);
// 读取特征值看小节点是否读取完毕
}
else
{
// 计数器加1,重新发送该数据包
dataTransferCounter.addCount();
if
(dataTransferCounter.getCount() <= dataTransferCounter.getMaxCount()){
gatt.writeCharacteristic(characteristic);
}
}
}
else
{
// 对特征值2进行写操作(用于提示小节点,手机已读取完数据包)
if
(status == BluetoothGatt.GATT_SUCCESS) {
if
(writeAfterReadCounter !=
null
) {
writeAfterReadCounter.close();
writeAfterReadCounter =
null
;
}
// 等待100ms之后再读取
try
{
Thread.sleep(
100
);
}
catch
(InterruptedException e) {
e.printStackTrace();
}
// 再读取特征值2,确认写操作成功,然后断开连接
gatt.readCharacteristic(characteristic);
}
else
{
if
(DBG){Log.d(BLUETOOTH_INFO,
"onCharacteristicWrite:status---> failed"
);}
// 写失败之后,开启超时计数器,超时之后直接断开连接
if
(writeAfterReadCounter ==
null
) {
writeAfterReadCounter =
new
Counter(
10
,
"writeAfterReadCounter"
,
new
CounterTask() {
@Override
public
void
run() {
writeAfterReadCounter =
null
;
hasDataToReceive =
false
;
disconnect();
}
});
writeAfterReadCounter.start();
}
writeAfterReadCounter.addCount();
if
(writeAfterReadCounter.getCount() <= writeAfterReadCounter.getMaxCount()) {
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
// 根据hasDataToReceive标志位,写全1或全0
if
(hasDataToReceive) {
characteristic.setValue(GattConstants.FrameInfo.ALL_ONE_RSP.getBytes());
}
else
{
characteristic.setValue(GattConstants.FrameInfo.ALL_ZERO_RSP.getBytes());
}
gatt.writeCharacteristic(characteristic);
}
}
}
}
};
// 使用handlerThread线程处理handler的消息队列,而不直接使用handler
handlerThread =
new
HandlerThread(
"scan thread"
);
handlerThread.start();
handler =
new
Handler(handlerThread.getLooper());
runnable =
new
Runnable() {
@Override
public
void
run() {
startSearch();
}
};
startSearch();
}
@SuppressWarnings
(
"deprecation"
)
public
void
startSearch() {
// 检查蓝牙设备是否开启
if
(!mAdapter.isEnabled()) {
mAdapter.enable();
}
// 如果正在扫描,则停止扫描,然后重新开始扫描.若持续扫描的话,只会收到设备的第一条广播包
if
(isScaning) {
isScaning =
false
;
mAdapter.stopLeScan(mLeScanCallback);
postTime = (
short
)(
0.5
* GattConstants.POST_PERIOD);
}
else
{
// 采用UUID方式进行设备过滤存在问题,不使用mAdapter.startLeScan(serviceUuids, callback)该方法
isScaning =
true
;
mAdapter.startLeScan(mLeScanCallback);
postTime = GattConstants.POST_PERIOD;
}
handler.postDelayed(runnable, postTime);
}
// 官方Demo使用address作为参数
@SuppressWarnings
(
"deprecation"
)
private
void
connect(String bleAddress) {
if
(!isConnected) {
handler.removeCallbacks(runnable);
if
(isScaning) {
isScaning =
false
;
mAdapter.stopLeScan(mLeScanCallback);
}
// 主要用在连接状态改变回调函数中,当断开连接时,用于判定是否真正需要断开连接,和连接失败进行区分
isNeedConnect =
true
;
BluetoothDevice device = mAdapter.getRemoteDevice(bleAddress);
bluetoothGatt = device.connectGatt(context,
false
, gattCallback);
}
}
private
void
disconnect() {
if
(bluetoothGatt ==
null
) {
return
;
}
isConnected =
false
;
firstScanToSend =
true
;
firstScanToReceive =
true
;
// close和disconnect的区别: close除了断开连接外,还会释放掉所有资源,导致不可以直接在后面的操作中用gatt对象的connect直接连接,
// 而disconnect并不释放资源 ,所以,所有的资源还保存着,就可以用Gatt的connect进行简单恢复连接,
// 而不是在device那一层进行操作
// 调用disconnect断开连接,然后在回调函数中使用close()释放资源
bluetoothGatt.disconnect();
}
}
|