Android проблема памяти при сканировании блютуса с нитью и обработчиком - PullRequest
1 голос
/ 09 февраля 2020

Я использую нить и обработчик для получения службы сканирования Bluetooth определенного периода и частоты сканирования (сканирование 1 с, сон 1 с, сканирование 1 с и т. Д. c) с помощью BluetoothLeScanner (фактически мигрирующего из BluetoothAdapter). Однако со временем я понимаю, что это пожирает память.

Затем я попытался использовать профилировщик, чтобы увидеть, что произошло, и обнаружил, что что-то зацикливается рекурсивно. Я проверил свой код и не смог найти проблему. Кто-нибудь может помочь / столкнулся с той же проблемой?

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);
        }
    }
}


enter image description here записано в более раннее время

c записано позднее

РЕДАКТИРОВАТЬ: Я удалил нить и обработчик, как я перепутал использование BluetoothLeScanner с BluetoothAdapter. ScanLeDevice () теперь вызывается из основного потока, как предложено @ greeble31

1 Ответ

1 голос
/ 09 февраля 2020

Учтите следующее:

scanLeDevice() вызывается в бесконечном l oop и всегда с параметром true.

scanLeDevice() возвращается почти сразу (1 мс или меньше).

Каждый вызов scanLeDevice() создает новый Handler и новый анонимный Runnable. Привязка Runnable к Handler включает Message (по одному на каждый вызов postDelayed()).

Вы опустили определение SCAN_PERIOD в своем сообщении, но я ' Я собираюсь сделать обоснованное предположение и сказать, что это 60000 (1 минута). Это означает, что каждый новый Handler должен существовать в течение 1 минуты, потому что он должен удерживать Message в течение 1 минуты, потому что он отслеживает Runnable, который должен быть выполнен, когда истекает эта минута.

In Другими словами: вы вызываете scanLeDevice() примерно 1000 раз в секунду, и каждый вызов создает 3 взаимосвязанных объекта, которые должны существовать не менее 1 минуты.

Вероятно, ваша архитектурная ошибка включала bleScanningThread. scanLeDevice() можно смело вызывать в главном потоке. Это нужно назвать только один раз. Он немедленно вернется, но сканирование все равно будет проводиться (ОС) в фоновом режиме. ScanCallback будет выполняться при необходимости, даже если вы не указали дополнительный поток. Сканирование прекратится, когда ваш postDelayed() Runnable будет выполнен; это, вероятно, то, что вы хотели с самого начала.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...