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

Android中BLE设备断开重连异常:Nougat版本重连触发无响应求助

BLE断开后重连在Android Nougat出现ANR的解决方案

我碰到过不少开发者在Android 7.0(Nougat)及以上版本遇到BLE断开后重连触发“应用无响应”的问题,结合你的代码来看,这主要是因为Nougat对BLE连接生命周期的管控更严格,加上你的断开逻辑可能存在主线程阻塞或者状态不同步的问题。下面给你一步步拆解解决方案:

1. 把BLE断开操作移到子线程执行

BLE相关的GATT操作(包括断开)绝对不能放在主线程里跑,Nougat开始系统对主线程耗时操作的阈值卡得更严,一旦disconnect里有阻塞操作,直接就会触发ANR。

修改你的mBTLE_Service里的disconnect方法,把所有GATT操作封装到子线程:

public void disconnect() {
    new Thread(new Runnable() {
        @Override
        public void run() {
            if (mBluetoothGatt != null) {
                // 先关闭所有特征通知,避免残留回调
                for (BluetoothGattService service : mBluetoothGatt.getServices()) {
                    for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) {
                        if ((characteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
                            mBluetoothGatt.setCharacteristicNotification(characteristic, false);
                        }
                    }
                }
                // 先断开GATT连接,再关闭资源
                mBluetoothGatt.disconnect();
                mBluetoothGatt.close();
                mBluetoothGatt = null;
            }
        }
    }).start();
}

2. 等待断开完成的回调,再执行重连

别着急在调用disconnect后立刻发起重连,必须等系统返回断开成功的回调。你需要在BluetoothGattCallback里监听连接状态变化:

@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
    super.onConnectionStateChange(gatt, status, newState);
    if (newState == BluetoothGatt.STATE_DISCONNECTED) {
        // 标记设备已完全断开,这里可以发广播通知Activity
        Intent disconnectIntent = new Intent("BLE_DEVICE_DISCONNECTED");
        sendBroadcast(disconnectIntent);
        // 如果需要自动重连,也在这里触发,不要在其他地方直接调用重连
        // reconnectDevice();
    }
}

然后在你的Activity里注册广播接收器,收到断开完成的通知后再处理重连或者页面操作,避免状态冲突。

3. 优化你的onBackPressed对话框逻辑

用户点击“OK”后,最好给个加载提示,让用户知道正在处理,同时等待断开完成再关闭对话框或结束Activity:

@Override
public void onBackPressed() {
    AlertDialog.Builder adb = new AlertDialog.Builder(ActivityName.this);
    adb.setTitle("DISCONNECT");
    adb.setCancelable(true);
    adb.setMessage("Do you want to disconnect");
    adb.setPositiveButton("OK", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            // 显示断开中的加载提示
            ProgressDialog progressDialog = ProgressDialog.show(ActivityName.this, "", "Disconnecting...", true);
            
            // 临时注册广播接收器监听断开完成
            BroadcastReceiver disconnectReceiver = new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    progressDialog.dismiss();
                    unregisterReceiver(this);
                    dialog.dismiss();
                    // 这里可以安全地结束Activity或者执行其他操作
                    finish();
                }
            };
            registerReceiver(disconnectReceiver, new IntentFilter("BLE_DEVICE_DISCONNECTED"));
            
            // 发起断开操作
            mBTLE_Service.disconnect();
        }
    });
    adb.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
            dialog.dismiss();
        }
    });
    AlertDialog alertDialog = adb.create();
    alertDialog.show();
}

4. 检查Nougat的BLE权限要求

Nougat开始BLE扫描需要位置权限,确保你的应用已经声明并请求了相关权限:
在AndroidManifest.xml中添加:

<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- 针对Android 12及以上的权限 -->
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />

并且在运行时动态请求ACCESS_FINE_LOCATION权限,否则BLE操作会静默失败,间接导致ANR。

总结一下:核心就是避免主线程执行BLE操作、确保断开状态同步后再重连、适配系统的权限要求,这几点搞定后Nougat上的ANR问题应该就能解决了。

内容的提问来源于stack exchange,提问作者Bichitra Pradhan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:34:51