Android 使用线程和处理程序扫描蓝牙时出现内存问题

Android memory issue when scanning bluetooth with thread and handler

我正在使用线程和处理程序通过 BluetoothLeScanner(实际上是从 BluetoothAdapter 迁移而来)实现特定扫描周期和频率(扫描 1s、睡眠 1s、扫描 1s 等)的蓝牙扫描服务。然而,随着时间的推移,我意识到它正在消耗内存。

然后我尝试使用探查器查看发生了什么,我发现有一些递归循环。我检查了我的代码,但找不到问题所在。任何人都可以 help/encountered 同样的问题?

public class BleDetectionService extends Service {

    private static Handler handler;
    private static final long SCAN_PERIOD = 1100;

    ...

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        ....

        startBLEScanning();
        return super.onStartCommand(intent, flags, startId);

    }

    private void startBLEScanning() {
        mLeDeviceAdapter = new LeDeviceAdapter();
        mScanning = true;

        Toast.makeText(this, "BLE Service sucessfully started", Toast.LENGTH_SHORT).show();

        bleScanningThread = new Thread(new Runnable() {
            @Override
            public void run() {
                Looper.prepare(); 
                while (mScanning) {
                    scanLeDevice(true);
                }
            }
        }, "BLE Scanning Thread");

        bleScanningThread.start();
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            handler = new Handler();
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    bluetoothLeScanner.stopScan(scanCallback);
                }
            }, SCAN_PERIOD);

            // filter
            ScanFilter.Builder builder = new ScanFilter.Builder();
            ScanFilter filter = builder.build();
            ArrayList<ScanFilter> filters = new ArrayList<>();
            filters.add(filter);

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

            bluetoothLeScanner.startScan(filters, settings, scanCallback);

        } else {
            bluetoothLeScanner.stopScan(scanCallback);
        }
    }
}


早前记录

稍后记录

编辑: 我已经删除了线程和处理程序,因为我混淆了 BluetoothLeScanner 和 BluetoothAdapter 的使用。按照 @greeble31

的建议,现在从主线程调用 scanLeDevice()

考虑以下几点:

scanLeDevice() 在永无止境的循环中被调用,并且始终带有参数 true

scanLeDevice() return 几乎立即(1 毫秒或更短)。

每次调用 scanLeDevice() 都会创建一个新的 Handler 和一个新的匿名 RunnableRunnableHandler 的绑定涉及 Message(每次调用 postDelayed())。

您在 post 中省略了 SCAN_PERIOD 的定义,但我将进行有根据的猜测,并说它是 60000(1 分钟)。这意味着每个新的 Handler 必须存在 1 分钟,因为它需要保持 Message 1 分钟,因为它正在跟踪 Runnable,该 Runnable 需要在该分钟到期时执行。

换句话说:您每秒调用 scanLeDevice() 大约 1000 次,每次调用都会创建 3 个必须存在至少 1 分钟的相互关联的对象。

您的架构错误可能包括 bleScanningThreadscanLeDevice() 可以在主线程上安全调用。它只需要被调用一次。它将立即 return,但扫描仍将在后台进行(由 OS)。 ScanCallback 将在适当的时候执行,即使您没有提供额外的线程。当您的 postDelayed() Runnable 执行时,扫描将停止;这可能是您一开始的意图。