You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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的读取长度和解析方法需与协议完全一致
  • 忽略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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 17:10:24