所以我能够在正常情况下连接到BLE设备。我想要做的是处理异常情况,例如当与设备的连接失败或已建立的连接丢失时(可能是从悬崖上抛出或被公共汽车撞到)
我使用CyPress BLE模块对此进行测试,我正在进行的其中一项测试是断开模块的电源。但是,onConnectionStateChange永远不会被调用!我所看到的只是成功的联系。它将花费数小时尝试连接,并且永远不会放弃。我会延迟取消连接尝试,但是没有办法取消BluetoothDevice上的连接尝试(我知道)!据我所知,它会继续尝试,直到电池电量耗尽。
这是我的onConnectionStateChange现在在Gatt回调中的样子。请注意,我试图捕获并记录涉及任何类型的连接状态更改的任何类型的回调...除非连接成功,否则永远不会被调用。请注意,这是代码不在活动本身。它位于一个由单身人士持有的物体中。 (我希望保持多个活动之间的连接)
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
mGatt = gatt;
Logy.CallPrint(LOGY_ENABLE, CLASSNAME, "Status: "+status+ " Newstate: "+newState);
switch(status)
{
case BluetoothGatt.GATT_SUCCESS:
mReconnectAttempts = MAX_ATTEMPTS;
if(newState == BluetoothGatt.STATE_CONNECTED)
{
DispatchEvent(Event.Type.BT_ON_CONNECT);
bIsConnected = true;
gatt.discoverServices();
} else if (newState == BluetoothGatt.STATE_DISCONNECTED)
{
DispatchEvent(Event.Type.BT_ON_DISCONNECT);
bIsConnected = false;
}
break;
default:
if(newState == BluetoothGatt.STATE_DISCONNECTED)
{
bIsConnected = false;
if(mReconnectAttempts > 0)
{ // if we have attempts left, auto attempt to reconnect
DispatchEvent(Event.Type.BT_RECONNECTING);
mReconnectAttempts--;
gatt.connect();
bIsConnected = false;
}
else
{
mReconnectAttempts = MAX_ATTEMPTS;
DispatchEvent(Event.Type.BT_ON_CONNECT_FAIL);
bIsConnected = false;
}
} else {
Logy.CallPrint(LOGY_ENABLE, CLASSNAME, "onConnectionStateChange: Failed?");
}
}
super.onConnectionStateChange(gatt, status, newState);
}
无法检测断开连接是我的代码中的其他问题,例如我显示进度对话框,指示应用程序正在连接到BLE设备。那个对话永远不会消失,因为事件" On Connect Fail"永远不会被抛出。
答案 0 :(得分:8)
我认为您所寻找的是Bluetooth Supervision timeout
,根据Bluetooth LE specifications:
一个参数,用于定义在连接被视为丢失之前两个接收的数据包PDU之间的最大时间
Android上的默认Supervision timeoout
设置为20秒(取决于Android版本和设备)。例如,here是Android 5.1上Supervision Timeout
的值。
没有用于设置此参数的API,因此您必须等待20秒(具体取决于您的Android版本和设备)才能在关闭电源后获得状态为onConnectionStateChange
的{{1}}回调BLE模块
答案 1 :(得分:6)
这个答案与埃米尔的答案一致。
我编写了一个测试应用程序,其中一个Activity在Moto G4 Play Android 6.0.1(Marshmellow:API23)和基于Laird BL600的外围设备上运行
我打算发布一些日志 - 但它们的格式不是很好 - 所以我只是描述结果。
像往常一样,外围设备做广告和中央扫描,并获得了一个设备实例。
问题并未明确说明第一次连接的确切方式,但让我们假设它是'autoconnect'假,形式为
mBluetoothGatt = device.connectGatt(mContext, false, mGattCallback);
(这是测试App中使用的唯一连接方式)
这给出了BluetoothGatt
的实例,并且如问题中所述,然后通过回调异步报告事件,
但是在发生任何连接事件之前,还有一个BluetoothGatt
的实例可以调用disconnect()
。
disconnect()
州的API文档 - 尤其是','之后的部分
BluetoothGatt.disconnect()
断开已建立的连接,或取消当前正在进行的连接尝试。
要释放GATT资源,断开连接后,测试应用程序也会始终调用
mBluetoothGatt.close();
以下是一些不同的场景
device.connectGatt() - 外围广告 - 建立连接 - 然后是mBluetoothGatt.disconnect()和close()。
结果:这是正常成功的连接,然后中央设备在代码中关闭连接。按预期收到回叫事件。当中央在代码中断开连接时,基础蓝牙服务将断开连接,并且外围设备将发生断开连接事件 。
device.connectGatt() - 外围广告 - 连接 - 然后关闭外围设备。
结果:这是正常的成功连接,按预期回调事件,然后由外围设备断开连接。外设指示BleGapSvcInit中的首选连接监督超时,这在连接参数更新中由Central确认。在外围设备断开连接后,在连接监督超时后,中心发生断开连接事件。 (重复8秒和4秒监督超时) 。
device.connectGatt() - 但外围设备已停止广告,允许连接尝试超时。
结果:(这是问题的具体情况)30秒后,可能是手机上蓝牙服务的连接超时,
有一个onConnectionStateChange
事件,表明新的连接状态是Disconnected - with(error)status 133。
仍然记得调用mBluetoothGatt.close()
否则会发生接口泄漏,并在下一个客户端接口上进行后续连接
。
device.connectGatt() - 外围设备仍处于广告状态,但使用mBluetoothGatt.disconnect()和close()在200ms后取消连接。
结果:(我发现这个案例最有趣,如果也是最不可能在实际应用中发生的话)有时,(大约十分之一) 底层蓝牙服务确实连接到了外围设备;看到连接,然后断开连接;即使应用程序没有看到 这些事件在回电中。有时,尽管就App而言,应用程序已断开连接,即基础蓝牙电话服务 连接到外围设备 - 并在我的测试中保持连接几分钟,直到我超时! - 关闭BT服务或外围设备。
答案 2 :(得分:3)
首先,如果建立的连接被丢弃,则在监督超时已过时,应该会发生断开连接的状态更改事件。否则Android中会出现一些错误。
现在关于连接尝试。
使用connectGatt创建BluetoothGatt对象并将auto connect参数指定为true或在现有BluetoothGatt对象上执行connect方法时,手机将处于始终无限期尝试连接到设备并重新连接的状态设备是否因任何原因断开连接,直到您调用断开连接或关闭gatt对象为止。
因此,如果您想在一段时间后中断连接,只需设置任何类型的计时器,当它被触发时,会调用gatt对象上的disconnect(或者如果您不再需要它,则关闭)。
另请注意,newState断开连接时onConnectionStateChange的status参数未明确定义。在较旧的Android版本中,它通常包含0或133,而在较新版本中通常是蓝牙标准的断开原因的错误代码。
此外,如果您在之前没有连接状态更改事件的情况下获得断开连接状态更改事件,则通常表示内部蓝牙堆栈中出现了问题(除非您使用非自动连接,因此您总是断开连接一些超时后的状态改变事件)。然后我建议您关闭gatt对象,稍后再试。