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

Android BLE应用RSSI读取40分钟后触发DeadObjectException问题

问题分析与解决方案

兄弟,我之前碰到过几乎一模一样的问题!先给你拆解核心问题,再给你落地的解决办法:

核心问题拆解

  1. DeadObjectException的本质:你的mBluetoothGatt对象虽然不为空,但它内部绑定的蓝牙服务Binder代理已经失效了——系统可能因为长时间频繁的RSSI调用、资源回收或者蓝牙服务临时重启,切断了这个跨进程连接。
  2. 为什么try-catch没触发:readRemoteRssi()是异步跨进程调用,DeadObjectException是在系统蓝牙服务的Binder线程里抛出的,根本不会回到你调用的线程的try块中,所以你的catch完全抓不到这个异常!
  3. RSSI调用的恶性循环:你原来的逻辑是不管上一次RSSI读取成功与否,都会每隔1秒发一次请求,一旦Binder失效,就会不断堆积失败的调用,进一步加剧系统蓝牙服务的压力,最终导致整个Gatt连接彻底失效,数据停止更新。

具体解决方案

1. 新增连接状态追踪,别只靠mBluetoothGatt != null

首先在你的类里加几个状态变量,用来追踪连接状态和重试次数:

// 记录当前蓝牙连接状态
private int mConnectionState = BluetoothProfile.STATE_DISCONNECTED;
// RSSI读取最大重试次数
private static final int MAX_RSSI_RETRY = 3;
private int mRssiRetryCount = 0;

然后重写BluetoothGattCallback的连接状态回调,实时更新状态:

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    super.onConnectionStateChange(gatt, status, newState);
    mConnectionState = newState;
    
    if (newState == BluetoothProfile.STATE_DISCONNECTED) {
        // 连接断开时,主动释放Gatt资源,避免无效对象占着坑
        if (mBluetoothGatt != null) {
            mBluetoothGatt.close();
            mBluetoothGatt = null;
        }
        // 这里写你的重新连接逻辑,比如调用设备的connect方法
    }
}

2. 改成“回调驱动”的RSSI调用逻辑

原来的无条件循环调用是大坑,改成只有上一次RSSI读取成功后,才发送下一次请求,避免无效请求堆积:

首先删掉原来的checkRssi()方法,然后重写onReadRemoteRssi回调:

@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
    super.onReadRemoteRssi(gatt, rssi, status);
    
    if (status == BluetoothGatt.GATT_SUCCESS) {
        // RSSI读取成功:重置重试计数,发送下一次请求
        mRssiRetryCount = 0;
        bleHandler.sendEmptyMessageDelayed(MSG_CHECK_RSSI, 5000); // 5秒间隔比1秒更稳妥,减少系统压力
        // 这里处理你的RSSI数据,更新UI/图表等逻辑
    } else {
        // 读取失败:增加重试计数,触发重试逻辑
        mRssiRetryCount++;
        handleRssiRetry();
    }
}

// 处理RSSI读取失败的重试逻辑
private void handleRssiRetry() {
    if (mRssiRetryCount < MAX_RSSI_RETRY) {
        // 还在重试次数内,1秒后重试
        bleHandler.sendEmptyMessageDelayed(MSG_CHECK_RSSI, 1000);
    } else {
        // 重试次数耗尽,触发重新连接
        mRssiRetryCount = 0;
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
            // 延迟3秒后尝试重新连接,给系统一点缓冲时间
            bleHandler.postDelayed(() -> {
                if (mBluetoothGatt != null) {
                    mBluetoothGatt.connect();
                }
            }, 3000);
        }
    }
}

3. 修正Handler里的RSSI触发逻辑

现在Handler里只需要做状态检查,然后发起读取:

case MSG_CHECK_RSSI:
    Log.i(HANDLER_TAG, "MSG_CHECK_RSSI");
    // 先检查连接状态是否正常,再发起读取
    if (mBluetoothGatt != null && mConnectionState == BluetoothProfile.STATE_CONNECTED) {
        try {
            mBluetoothGatt.readRemoteRssi();
        } catch (RuntimeException e) {
            // 兜底捕获可能的RuntimeException,虽然之前没触发,但加上更保险
            e.printStackTrace();
            mRssiRetryCount++;
            handleRssiRetry();
        }
    } else {
        // 连接状态异常,直接触发重试/重连
        mRssiRetryCount++;
        handleRssiRetry();
    }
    break;

4. 生命周期里正确释放资源

在Activity/Fragment销毁时,一定要清理Gatt和Handler资源,避免内存泄漏:

@Override
protected void onDestroy() {
    super.onDestroy();
    // 关闭Gatt连接
    if (mBluetoothGatt != null) {
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }
    // 移除Handler所有未执行的消息
    if (bleHandler != null) {
        bleHandler.removeCallbacksAndMessages(null);
    }
}

额外排查要点

  • 可以监听系统蓝牙状态变化,比如注册BluetoothAdapter.ACTION_STATE_CHANGED广播,当蓝牙重启时,主动触发重连逻辑
  • 检查BLE设备本身的固件,有些设备长时间连续响应RSSI请求会进入休眠或者拒绝响应

内容的提问来源于stack exchange,提问作者Geeky bean

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 08:50:05