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

Android多BLE外围设备连接时通知处理与数据丢失问题求解

问题根因

Android 原生 BLE 栈默认会将所有 BluetoothGattCallback 的回调事件分发到同一个共享 Binder 线程,当多台设备同时以 50Hz 频率推送数据时,单线程处理速度跟不上回调量,就会导致事件队列溢出、数据丢失,这和你是否存储独立 BluetoothGatt 实例没有关系。

可落地的解决思路

1. 回调内仅做数据转发,不处理业务逻辑

你当前在 onCharacteristicChanged 中直接执行 acc.update()、打印日志的操作都会占用回调线程的时间,多设备并发时很容易阻塞后续回调。
正确做法是拿到数据后立刻转发到异步线程处理,回调函数本身尽快返回:

// 每个TTGODevice持有专属的单线程池,避免多设备数据处理互相干扰
private final ExecutorService dataProcessExecutor = Executors.newSingleThreadExecutor();

@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
    final byte[] data = characteristic.getValue();
    // 直接扔到异步线程处理,立刻返回
    dataProcessExecutor.execute(() -> {
        acc.update(data);
        // 业务日志也放到异步线程打
        Log.d(TAG, "onCharacteristicChanged: " + Thread.currentThread().getName());
    });
}

2. 为每个设备分配独立的回调线程

Android 6.0 及以上版本的 connectGatt 方法支持传入自定义 Handler,你可以为每台设备单独创建带 Looper 的线程处理回调,避免共享线程阻塞:

public class TTGODevice {
    private HandlerThread gattCallbackThread;
    private Handler gattCallbackHandler;

    public void connect(boolean autoConnect) {
        // 每个设备单独创建回调线程
        gattCallbackThread = new HandlerThread("GattCallback_" + device.getAddress());
        gattCallbackThread.start();
        gattCallbackHandler = new Handler(gattCallbackThread.getLooper());
        // 传入自定义Handler,回调就会跑在专属线程上
        server = device.connectGatt(context, false, bluetoothGattCallback, 
                BluetoothDevice.TRANSPORT_LE, gattCallbackHandler);
    }

    // 设备断开时记得销毁线程,避免内存泄漏
    public void release() {
        if (server != null) {
            server.close();
            server = null;
        }
        if (gattCallbackThread != null) {
            gattCallbackThread.quitSafely();
            gattCallbackThread = null;
            gattCallbackHandler = null;
        }
        dataProcessExecutor.shutdown();
    }
}

3. 调整 BLE 连接参数提升传输效率

连接成功后主动申请高连接优先级,将连接间隔压到最小(通常7.5ms),足够支撑50Hz(20ms间隔)的稳定传输:

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    super.onConnectionStateChange(gatt, status, newState);
    if (newState == BluetoothProfile.STATE_CONNECTED && status == BluetoothGatt.GATT_SUCCESS) {
        // 申请高优先级连接,减少传输延迟
        gatt.requestConnectionPriority(BluetoothGatt.CONNECTION_PRIORITY_HIGH);
        // 可选:申请稍大的MTU,避免偶尔的额外数据导致分包
        gatt.requestMtu(32);
    }
}

关于Fragment、ViewModel的疑问

这两个组件和你的BLE多连接丢包问题没有直接关联,他人提出该建议的核心目的是:将BLE连接逻辑放到生命周期更长的ViewModel/保留实例Fragment中,避免Activity销毁重建时触发断开重连,导致不必要的数据包丢失,你不需要优先花时间调整这部分逻辑,先优化上述BLE相关逻辑即可。


内容的提问来源于stack exchange,提问作者Ehsan Partovi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 03:24:01