You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Android BLE扫描线程+Handler实现引发内存泄漏问题求助

BLE扫描服务内存飙升与递归循环问题排查修复

Hey,我之前也碰到过几乎一模一样的问题!先帮你拆解下代码里的核心坑:

问题根源分析

  • 无限循环无休眠:你在startBLEScanning()里启动的线程,用while(mScanning)做了一个无任何休眠的死循环,疯狂调用scanLeDevice(true)。这意味着线程会在极短时间内触发成百上千次扫描请求,完全没有给扫描停止的时间。
  • 重复创建Handler:每次调用scanLeDevice(true)都会新建一个Handler对象,并且post延迟停止扫描的任务。这些Handler和延迟任务会不断堆积在消息队列里,加上循环触发的扫描请求,直接导致内存占用飙升,Profiler检测到的递归循环就是因为这种无节制的重复调用和任务堆积造成的。
  • 扫描逻辑冲突:你的SCAN_PERIOD设为1100ms,但循环会在扫描还没到停止时间就再次启动扫描,相当于多个扫描任务同时运行,进一步加剧了资源消耗。

你的修复方向是对的!

你后来按照建议移除Thread和Handler,改用主线程调用scanLeDevice()的思路完全正确。这里给你补充一个更规范的循环扫描实现,确保扫描和休眠能正常交替:

private void startCycleScanning() {
    if (!mScanning) return;

    // 启动BLE扫描
    scanLeDevice(true);

    // SCAN_PERIOD后停止扫描,然后进入休眠
    new Handler(Looper.getMainLooper()).postDelayed(() -> {
        scanLeDevice(false);
        // 休眠1000ms后启动下一轮扫描
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
            startCycleScanning();
        }, 1000);
    }, SCAN_PERIOD);
}

// 调整scanLeDevice方法,避免重复创建Handler
private void scanLeDevice(final boolean enable) {
    if (enable) {
        // 只创建一次Handler或者复用主线程Handler
        if (handler == null) {
            handler = new Handler(Looper.getMainLooper());
        }
        handler.postDelayed(() -> {
            if (bluetoothLeScanner != null) {
                bluetoothLeScanner.stopScan(scanCallback);
            }
        }, SCAN_PERIOD);

        // 扫描过滤和设置逻辑保持不变
        ScanFilter filter = new ScanFilter.Builder().build();
        ArrayList<ScanFilter> filters = new ArrayList<>();
        filters.add(filter);

        ScanSettings settings = new ScanSettings.Builder()
                .setScanMode(ScanSettings.SCAN_MODE_BALANCED)
                .setReportDelay(0)
                .build();

        if (bluetoothLeScanner != null) {
            bluetoothLeScanner.startScan(filters, settings, scanCallback);
        }
    } else {
        if (bluetoothLeScanner != null) {
            bluetoothLeScanner.stopScan(scanCallback);
        }
    }
}

额外注意事项

  • 记得在服务的onDestroy()方法里,停止扫描并移除Handler的所有延迟任务,避免内存泄漏:
@Override
public void onDestroy() {
    super.onDestroy();
    mScanning = false;
    if (bluetoothLeScanner != null) {
        bluetoothLeScanner.stopScan(scanCallback);
    }
    if (handler != null) {
        handler.removeCallbacksAndMessages(null);
    }
}

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

火山引擎 最新活动