安卓BLE重新连接非常缓慢。

4

背景:

我有一个带有两种模式的BLE外设:“应用程序”和“引导程序”。在两种模式下,该设备都使用相同的MAC地址进行广告。

要从一种模式切换到另一种模式,BLE外设必须重新启动。这样做时,它必须断开任何活动的BLE连接。

BLE外设仅会在Bootloader模式下停留约5秒钟。如果在该窗口内没有人连接它,则会切换到Application模式。

问题:

Android重新连接到BLE设备需要很长时间,足以让我错过5秒钟的窗口。原始代码有几个层级到BluetoothGATT和BluetoothAdapter层,但调用序列归结为:

BluetoothGattCharacteristic c = mCharacteristics.get(POWER_STATE_UUID);
c.setValue(SHUTDOWN_VALUE);
mBluetoothGatt.writeCharacteristic(c);
// Signalled by BluetoothGattCallback.onCharacteristicWrite
bleWriteCondition.await();

mBluetoothGatt.disconnect();
// Wait for the underlying layer to confirm we're disconnected
while( mConnectionState != BluetoothProfile.STATE_DISCONNECTED ) {
    // Signalled by BluetoothGattCallback.onConnectionStateChange
    bleStateCondition.await(); 
}
mBluetoothGatt.connect();
while (mConnectionState != BluetoothProfile.STATE_CONNECTED) {
    // Signalled by BluetoothGattCallback.onConnectionStateChange
    bleStateCondition.await();
    if (bleStateCondition.stat != 0) {
        break;
    }
}

我是不是完全走错了路?我尝试在BluetoothGatt实例上调用close(),然后使用BluetoothDevice.connectGatt生成一个新实例,但我得到相同的极慢行为。

我在三星Galaxy S4上进行测试,API级别为21。


设备广告的频率是多少? - 323go
在 bootloader 模式下,每 100 毫秒执行一次。在应用程序模式下,每秒执行一次。 - James Whong
你解决了这个问题吗?我发现在失去与BLE设备的连接后,重新连接到同一外设需要确切的20秒时间,即使你手动调用disconnect()、close()、connect(),无论是使用直接连接还是后台连接。 - Mark Ch
1
我找到了一个解决方案,适用于某些版本的Android。我在外围设备的重新启动命令中安装了延迟,以便Android设备可以启动断开连接。因此,外围设备接收重新启动命令,但实际上直到Android端关闭连接后才重新启动。然后,Android可以重新连接到外围设备。显然,这只适用于您可以访问外围设备固件的情况,但我希望它有所帮助。 - James Whong
@James,谢谢,这是一个有趣的方法。我在外围设备重新启动之前添加了0.5秒的延迟,现在外围设备实际上有时间正确地断开连接,然后再进行电源循环。在某个较低层次上,断开连接的过程必须包括通知链接的另一端,因为现在安卓设备能立即断开连接并迅速重新连接。谢谢。 - Mark Ch
1个回答

3
这里的问题是Gatt连接调用发出了一个后台连接请求,这个调用可能需要很长时间才能导致连接成功。这里有两种类型的连接请求:直接连接与后台连接
最快获取连接的方法是进行扫描,并在找到您的设备后向其发出直接连接请求。由于扫描刚刚找到它,所以您知道它在那里,连接将很快完成。这比您的示例代码更复杂,但在您的小窗口内最有效。扫描是查找设备最具攻击性的方式。但是,如果您已经拥有设备对象,可以直接对该设备发起连接请求。
扫描使用以下代码发出:
scanner = bluetoothAdapter.getBluetoothLeScanner();
settings = new ScanSettings.Builder()
            .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
            .build();
filters = new ArrayList<ScanFilter>();
ScanFilter uuidFilter = new ScanFilter.Builder()
            .setServiceUuid(YOUR_SERVICE_UUID).build();
filters.add(uuidFilter);
scanner.startScan(filters, settings, myScanCallback);

在扫描回调中找到您的设备后,通过以下方法调用发出直接连接请求:
myGatt = myDevice.connectGatt(this, false, myGattCallback);

关键部分是参数为false。如果设备未找到,则连接请求将在约30秒后超时。


你有测试过这段代码和你的BLE设备吗?目前,我在从Android 5连接时遇到了连接问题。 - UVM
这是从一个部署在现场的应用程序中获取的代码。此问题和答案特定于获取连接所需的时间,它并不是连接到BLE设备的完整解决方案,其比上述复杂得多。 - pyrrhoofcam

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接