如何在GATT服务器关闭时通知客户端并更新其状态栏?
解决GATT服务器关闭时客户端状态不更新的问题
问题根源
直接调用mGattServer.close()会让服务器立即终止所有连接,但不会主动向客户端发送断开通知,导致客户端的BluetoothGattCallback无法触发onConnectionStateChange回调,状态栏也就无法更新。另外你之前的disconnectFromGattServer函数没有等待异步断开操作完成就直接关闭服务器,所以没起到作用。
解决方案
1. 完善服务器端断开逻辑,等待所有客户端断开后再关闭服务器
修改stopServer和断开连接的逻辑,通过GattServerCallback跟踪连接状态,确保所有客户端断开后再关闭服务器:
// 新增变量跟踪当前连接的客户端数量 private var connectedClientCount = 0 // 在GattServerCallback中更新连接计数 private val gattServerCallback = object : GattServerCallback() { override fun onConnectionStateChange(device: BluetoothDevice, status: Int, newState: Int) { super.onConnectionStateChange(device, status, newState) if (newState == BluetoothProfile.STATE_CONNECTED) { connectedClientCount++ devicesArrayList.add(device) } else if (newState == BluetoothProfile.STATE_DISCONNECTED) { connectedClientCount-- devicesArrayList.remove(device) // 当最后一个客户端断开时,关闭服务器 if (connectedClientCount == 0) { mGattServer?.close() mGattServer = null } } } } // 修改disconnectFromGattServer函数,遍历副本避免并发修改问题 fun disconnectFromGattServer() { val devicesCopy = ArrayList(devicesArrayList) devicesCopy.forEach { device -> mGattServer?.cancelConnection(device) } } // 修改stopServer函数,先触发断开所有连接,等待回调中完成服务器关闭 fun stopServer() { mGattServer?.let { disconnectFromGattServer() } }
2. 客户端侧增加容错检测
即使服务器端处理完善,也可能存在网络异常导致客户端收不到断开通知的情况,客户端可以定期检测连接状态:
// 客户端的BluetoothGattCallback中增加连接状态跟踪 private var isConnected = false private val gattCallback = object : BluetoothGattCallback() { override fun onConnectionStateChange(gatt: BluetoothGatt?, status: Int, newState: Int) { super.onConnectionStateChange(gatt, status, newState) isConnected = newState == BluetoothProfile.STATE_CONNECTED // 更新状态栏 updateStatusBar(isConnected) } override fun onCharacteristicRead(gatt: BluetoothGatt?, characteristic: BluetoothGattCharacteristic?, status: Int) { super.onCharacteristicRead(gatt, characteristic, status) if (status != BluetoothGatt.GATT_SUCCESS && isConnected) { // 读取失败,判定连接已断开 isConnected = false updateStatusBar(false) } } } // 定期检测连接状态,每隔5秒尝试读取特征值验证连接 private val connectionCheckTimer = Timer().scheduleAtFixedRate(object : TimerTask() { override fun run() { runOnUiThread { if (isConnected && gatt != null) { gatt.readCharacteristic(yourTargetCharacteristic) } } } }, 0, 5000)
3. 优化Activity的onDestroy逻辑
确保在销毁时正确触发断开流程,避免直接强制关闭:
override fun onDestroy() { super.onDestroy() if (preference_BluetoothMode == "Server") { bluetoothService?.stopServer() } else { bluetoothService?.disconnect() // 客户端记得关闭Gatt资源 bluetoothService?.closeGatt() } }
关键注意点
cancelConnection是异步操作,必须等待所有客户端的onConnectionStateChange回调触发后再关闭服务器。- 遍历连接设备时要使用副本,避免并发修改
devicesArrayList导致异常。 - 客户端侧增加主动检测,弥补被动回调的不足,提升状态更新的可靠性。
内容的提问来源于stack exchange,提问作者Renzo Sampietro
相关产品推荐
相关产品推荐

