如何检测安卓设备蓝牙即将关闭状态,实现断连前发送消息?
看来你找错了监听的广播类型啦!ACTION_BOND_STATE_CHANGED确实只关注配对设备的绑定状态变化,根本不会管本机蓝牙的开关状态。要监听本机蓝牙即将关闭的通知,你得用**BluetoothAdapter.ACTION_STATE_CHANGED**这个广播才行——它专门负责通知本机蓝牙适配器的状态变化,包括开启、正在开启、关闭、正在关闭这几个关键状态。
核心思路
你需要重点关注BluetoothAdapter.STATE_TURNING_OFF这个状态,这就是本机蓝牙即将关闭的信号,此时蓝牙还没完全断开连接,正是给已连接设备发送最后一条消息的黄金时机。而STATE_OFF是蓝牙已经完全关闭的状态,这时候再操作就来不及了。
修改后的代码实现
下面是调整后的完整代码,我保留了你原来的设备发现、配对状态监听逻辑,同时新增了本机蓝牙状态的处理:
class YourBluetoothManager( private val application: Application, private val deviceListener: ((List<BluetoothDevice>) -> Unit)? ) { // 已连接设备的Socket管理(需要你自己维护,用于发送最后消息) private val connectedDeviceSockets = mutableMapOf<BluetoothDevice, BluetoothSocket>() private val mBTReceiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { when (intent.action) { // 处理本机蓝牙状态变化(核心逻辑) BluetoothAdapter.ACTION_STATE_CHANGED -> { val currentState = intent.getIntExtra( BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR ) when (currentState) { BluetoothAdapter.STATE_TURNING_OFF -> { Log.d("MESSAGE", "本机蓝牙即将关闭,准备发送最后消息") // 执行给已连接设备发送最后消息的逻辑 sendFinalMessageToConnectedDevices() } BluetoothAdapter.STATE_OFF -> { Log.d("MESSAGE", "本机蓝牙已完全关闭") // 清空已连接设备的Socket缓存 connectedDeviceSockets.clear() } BluetoothAdapter.STATE_ON -> { Log.d("MESSAGE", "本机蓝牙已开启") fetchDevices() deviceListener?.invoke(devices) } } } // 处理设备发现(保留你原有的逻辑) BluetoothDevice.ACTION_FOUND -> { val device = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) if (device != null) { fetchDevices() deviceListener?.invoke(devices) } } // 处理配对状态变化(保留你原有的逻辑) BluetoothDevice.ACTION_BOND_STATE_CHANGED -> { val previousState = intent.getIntExtra( BluetoothDevice.EXTRA_PREVIOUS_BOND_STATE, BluetoothAdapter.ERROR ) val currentBondState = intent.getIntExtra( BluetoothDevice.EXTRA_BOND_STATE, BluetoothAdapter.ERROR ) // 可根据需要处理配对成功/失败等逻辑 } // 处理设备断开连接(可选,用于补充监听) BluetoothDevice.ACTION_ACL_DISCONNECTED -> { val disconnectedDevice = intent.getParcelableExtra<BluetoothDevice>(BluetoothDevice.EXTRA_DEVICE) Log.d("MESSAGE", "设备 ${disconnectedDevice?.name} 已断开连接") connectedDeviceSockets.remove(disconnectedDevice) } } } } init { fetchDevices() // 注册广播,添加所有需要监听的Action val intentFilter = IntentFilter().apply { addAction(BluetoothAdapter.ACTION_STATE_CHANGED) addAction(BluetoothDevice.ACTION_FOUND) addAction(BluetoothDevice.ACTION_BOND_STATE_CHANGED) addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED) } application.registerReceiver(mBTReceiver, intentFilter) } // 务必在组件销毁时注销广播,避免内存泄漏 fun destroy() { application.unregisterReceiver(mBTReceiver) } private fun fetchDevices() { // 你的设备获取逻辑(比如获取已配对设备) } private fun sendFinalMessageToConnectedDevices() { // 遍历所有已连接的设备Socket,发送最后消息 connectedDeviceSockets.forEach { (device, socket) -> try { val outputStream = socket.outputStream val finalMessage = "Goodbye!".toByteArray() outputStream.write(finalMessage) outputStream.flush() Log.d("MESSAGE", "已给设备 ${device.name} 发送最后消息") } catch (e: IOException) { Log.e("MESSAGE", "发送最后消息失败: ${e.message}") } } } // 假设你有一个方法用于记录已连接设备的Socket fun addConnectedDeviceSocket(device: BluetoothDevice, socket: BluetoothSocket) { connectedDeviceSockets[device] = socket } }
关键注意事项
- 权限申请:Android 12及以上需要申请
BLUETOOTH_CONNECT权限,Android 11及以下需要BLUETOOTH权限,记得在Manifest中声明并动态申请。 - 广播注销:动态注册的广播一定要在不需要的时候(比如Activity的
onDestroy或Service的onDestroy)注销,否则会引发内存泄漏。 - 已连接设备管理:你需要自己维护已连接设备的
BluetoothSocket实例,这样才能在STATE_TURNING_OFF状态下快速找到目标设备并发送消息。 - 消息发送时机:
STATE_TURNING_OFF是唯一能确保蓝牙还未完全断开的状态,一旦进入STATE_OFF或触发ACTION_ACL_DISCONNECTED,连接已经中断,无法再发送数据。
内容的提问来源于stack exchange,提问作者msc87
相关产品推荐
相关产品推荐

