Android蓝牙打印机:如何检测断开连接/写入失败事件?
嘿,这个问题我之前帮好几个开发者解决过——短消息断连能触发异常,但长消息打印到一半设备断开就毫无反应,确实挺闹心的。下面给你几个实用的方案,你可以根据自己的场景组合试试:
针对蓝牙打印机写入中途断连的错误检测方案
1. 主动轮询连接状态
系统自带的蓝牙连接回调有时候在数据传输中不够及时,你可以在写入长消息的过程中,定期检查套接字和设备的连接状态:
- 用
BluetoothSocket.isConnected()确认套接字是否存活,或者BluetoothDevice.getBondState()判断设备是否还处于绑定状态。 - 每500ms到1秒轮询一次,一旦发现连接断开,立刻终止写入并抛出异常。
// 写入长消息时的轮询示例 byte[] longData = getLongPrintMessage(); int offset = 0; while (offset < longData.length) { // 检查连接状态 if (!bluetoothSocket.isConnected()) { throw new IOException("Printer disconnected mid-write"); } // 分块写入(避免单次写入过大) int chunkSize = Math.min(1024, longData.length - offset); outputStream.write(longData, offset, chunkSize); offset += chunkSize; // 短暂休眠,减少轮询频率 Thread.sleep(500); }
注意:轮询间隔别太密,不然会占用过多CPU资源,500ms到1秒的区间比较合适
2. 给套接字设置超时+校验写入字节数
默认的蓝牙OutputStream没有超时机制,断连后写入操作可能会一直阻塞。你可以给套接字设置读写超时,这样超过指定时间没响应就会抛出异常:
// 设置3秒超时,根据你的打印速度调整 bluetoothSocket.setSoTimeout(3000);
另外,每次写入后检查实际写入的字节数,如果和预期不符,大概率是连接出问题了:
int expectedBytes = chunk.length; int actualBytes = outputStream.write(chunk); if (actualBytes != expectedBytes) { throw new IOException("Partial data written - connection may be lost"); }
3. 监听系统蓝牙断开广播
注册一个广播接收器,监听ACTION_ACL_DISCONNECTED事件,一旦收到目标打印机的断开通知,就标记连接状态为失效,在写入线程中实时检查这个标记:
// 初始化广播接收器 private BroadcastReceiver bluetoothDisconnectReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_ACL_DISCONNECTED.equals(action)) { BluetoothDevice disconnectedDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 对比你的打印机地址,确认是目标设备断开 if (disconnectedDevice.getAddress().equals(yourPrinterMacAddress)) { isPrinterConnected = false; } } } }; // 在写入线程中检查标记 while (offset < longData.length && isPrinterConnected) { // 写入逻辑... } if (!isPrinterConnected) { // 处理断连错误,比如提示用户重新连接 showErrorToast("Printer disconnected during printing"); }
记得在Activity销毁时注销广播接收器,避免内存泄漏
4. 分段写入+打印机确认机制(如果打印机支持)
很多商用蓝牙打印机支持反馈指令——每打印完一段数据会返回一个确认信号。你可以把长消息分成小块,每写完一块就读取打印机的确认:
List<byte[]> messageChunks = splitLongMessage(longMessage, 256); // 按256字节分块 for (byte[] chunk : messageChunks) { outputStream.write(chunk); outputStream.flush(); // 读取打印机的确认信号(假设返回0x00表示成功) byte[] response = new byte[1]; int readBytes = inputStream.read(response); if (readBytes == -1 || response[0] != 0x00) { throw new IOException("Printer failed to confirm chunk - connection lost"); } }
这个方案最可靠,但前提是你的打印机支持这类反馈指令,需要查一下打印机的SDK文档或者AT指令集。
这些方案可以组合使用,比如“轮询状态+广播监听”的组合,既能覆盖实时断连的场景,又能避免轮询的延迟问题。
内容的提问来源于stack exchange,提问作者dor506




