Android 12/11蓝牙SPP读取输入流抛出bt socket closed异常求助
Android蓝牙SPP输入流读取跨版本异常排查方向
问题场景
尝试通过SPP(串行端口协议)连接蓝牙设备并读取输入流,以下是运行在单线程执行器上的Future类call()方法:
public Void call() { while (!Thread.currentThread().isInterrupted()) { try { byte[] buffer = new byte[1024]; // reading PID btInputStream.read(buffer, 0, 1); int pId = ByteBuffer.wrap(buffer).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt(); buffer = new byte[1024]; btInputStream.read(buffer, 0, 1); int count = ByteBuffer.wrap(buffer).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt(); buffer = new byte[1024]; // reading payload btInputStream.read(buffer, 0, 2); int payload = ByteBuffer.wrap(buffer).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt(); buffer = new byte[1024]; // reading timestamp btInputStream.read(buffer, 0, 4); double timeStamp = ByteBuffer.wrap(buffer).order(java.nio.ByteOrder.LITTLE_ENDIAN).getInt(); // reading payload data buffer = new byte[payload - 4]; int read = btInputStream.read(buffer, 0, buffer.length); buffer = null; } catch (IOException e) { Log.e(Utils.TAG, "Error reading input stream. Exiting.", e); break; } } return null; }
在Android 13的Pixel设备上运行正常,但三星A22(Android 12)及部分Android 11设备运行一段时间后抛出IO异常,错误日志如下:
E/Explore: Error reading input stream. Exiting. java.io.IOException: bt socket closed, read return: -1 at android.bluetooth.BluetoothSocket.read(BluetoothSocket.java:751) at android.bluetooth.BluetoothInputStream.read(BluetoothInputStream.java:91) at com.mentalab.service.decode.ParseRawDataTask.call(MyTask.java:71) at com.mentalab.service.decode.ParseRawDataTask.call(MyTask.java:15) at java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637) at java.lang.Thread.run(Thread.java:1012)
排查方向
- 数据读取与解析不匹配:代码存在明显的字节长度错误,比如读取1字节后用
getInt()解析4字节int值,这会导致数据流同步失败,低版本Android设备对这类错误容错性更低。必须严格按照协议定义调整:- 若PID是1字节,改用
get()解析;若为4字节int,read时指定读取4字节 - count、payload、timestamp的读取长度和解析方法需与协议完全一致
- 若PID是1字节,改用
- 忽略
read()返回值:InputStream.read()无法保证一次性读取指定长度的字节,直接忽略返回值会导致数据截断,引发后续解析错误。建议封装工具方法循环读取直到获取足够字节:private int readFully(InputStream in, byte[] buffer, int offset, int length) throws IOException { int totalRead = 0; while (totalRead < length) { int read = in.read(buffer, offset + totalRead, length - totalRead); if (read == -1) { throw new IOException("Stream closed before reading all data"); } totalRead += read; } return totalRead; } - 蓝牙连接稳定性差异:不同品牌设备的蓝牙硬件实现差异大,三星A22等设备可能对数据流错误更敏感。可尝试:
- 调用
BluetoothSocket.setSocketTimeout()设置合理超时 - 增加心跳包机制维持连接活性
- 调用
- 线程与资源管理不严谨:当前循环仅检查线程中断状态,socket关闭后未确保资源释放。需在异常处理中补充关闭输入流和socket的逻辑,同时处理线程中断场景
- 系统权限与后台限制:Android 12及以下后台限制严格,检查是否已申请
BLUETOOTH_CONNECT、BLUETOOTH_SCAN权限,后台运行时是否持有唤醒锁以维持蓝牙连接
内容的提问来源于stack exchange,提问作者Salman Rahman
相关产品推荐
相关产品推荐

