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

Android端BLE工具无法断开并重新连接问题排查求助

问题分析与解决方案

首先,你的核心问题是按下返回键后,BLE断开操作的异步特性导致Activity重建时,全局的mBluetoothGatt还没被正确置空,再加上回调处理中的一些冗余操作,导致重新加载Activity时gatt != null仍为true。

一、当前代码的关键问题点

  1. 返回键点击时的操作顺序错误:
    你在点击返回键时立即调用了mContext.recreate(),但BleUtil.disconnect_tool()只触发了mBluetoothGatt.disconnect()——这是一个异步操作,onConnectionStateChanged回调还没执行完成,Activity就已经重建了,此时全局的mBluetoothGatt还是旧的引用,没有被置空。

  2. onConnectionStateChanged中的冗余与逻辑问题:

    • 你在STATE_DISCONNECTED分支里重复执行了gatt.close()和gatt = null,但方法参数gatt是局部变量,置空它不会影响全局的mBluetoothGatt(不过你已经处理了mBluetoothGatt = null,这部分没问题,但冗余代码容易混淆逻辑)。
    • 没有确保在断开连接后,彻底释放所有Gatt相关资源。

二、具体修复步骤

1. 改进返回键的点击逻辑:延迟页面操作,等待断开回调完成

不要在点击返回键后立即重建Activity,而是在onToolDisconnected回调中处理页面的回退与重建,确保断开操作完全完成:

llBack.setOnClickListener(new View.OnClickListener() { 
    @Override 
    public void onClick(View view) { 
        // 先发起断开请求,不要立即操作页面
        BleUtil.disconnect_tool();
    } 
});

然后在你的gattInterface.onToolDisconnected()回调中(假设这个回调是在Activity中实现的):

@Override
public void onToolDisconnected() {
    // 断开完成后,再处理页面回退与重建
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.popBackStack();
    recreate();
}

2. 完善BleUtil.disconnect_tool()方法

确保不仅断开连接,还要做安全检查(注意:不要在这里直接close(),因为disconnect()需要先触发onConnectionStateChanged,正确的关闭应该放在回调里):

public static void disconnect_tool() {
    if (mBluetoothGatt != null) {
        mBluetoothGatt.disconnect();
    }
}

3. 优化onConnectionStateChanged的断开逻辑

去掉冗余代码,确保全局mBluetoothGatt被正确置空,并释放资源:

private BluetoothGattCallback gattCallback = new BluetoothGattCallback() { 
    @Override 
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
        if (newState == STATE_CONNECTED) { 
            gattInterface.onToolConnected(); 
            gatt.discoverServices(); 
            Toast.makeText(activity,"Connected",Toast.LENGTH_SHORT).show(); 
        } else if (newState == STATE_DISCONNECTED) { 
            // 先关闭当前Gatt实例
            if (gatt != null) {
                gatt.close();
            }
            // 置空全局引用,确保新Activity启动时不会残留旧引用
            if (mBluetoothGatt != null) {
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
            gattInterface.onToolDisconnected(); 
            Log.d("checkdisco","disconn"); 
            Toast.makeText(activity,"Disconnected",Toast.LENGTH_SHORT).show(); 
        } 
    } 

    @Override 
    public void onServicesDiscovered(final BluetoothGatt gatt, final int status) { 
        if (status == BluetoothGatt.GATT_SUCCESS) { 
            gattInterface.onservicefound(gatt);
        }
    }
};

4. 额外:在Activity的onDestroy中添加安全兜底

为了避免异常情况(比如回调没触发),在Activity销毁时强制释放Gatt资源:

@Override
protected void onDestroy() {
    super.onDestroy();
    if (mBluetoothGatt != null) {
        mBluetoothGatt.disconnect();
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }
}

为什么这样修复?

  • 异步操作需要等待回调确认完成后再进行页面操作,避免资源引用残留。
  • 确保全局mBluetoothGatt被彻底置空,新Activity启动时不会检测到旧的引用。
  • 兜底的onDestroy处理可以防止极端情况下的资源泄漏。

内容的提问来源于stack exchange,提问作者Animesh Jena

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 07:22:58