Decreased BLE startScan erkannte Geräte auf Android 5.0 Lollipop

Kurze Version:

In meinen Tests mit Android 5.0 Lollipop habe ich bemerktandroid.bluetooth.le.BluetoothLeScanner erkennt BLE-Geräte seltener als Android 4.4 KitKat. Warum ist das so und gibt es eine Alternative?

Lange Version

Ich entwickle eine Android-Anwendung, die speziell für das Nexus 7-Tablet entwickelt wurde und sich auf die Erkennung von Bluetooth-Low-Energy-Geräten (BLE) konzentriert. Die App interessiert sich hauptsächlich für den RSSI-Wert der Beacons, um deren Nähe zum Tablet zu ermitteln. Dies bedeutet, dass ich keine Verbindung zum BLE-Gerät herstellen muss, da der RSSI-Wert an den Scan-Rückruf übergeben wird, wenn das Gerät erkannt wird.

In Android 4.4 KitKat, wenn ich @ anruBluetoothAdapter.startLeScan(LeScanCallback), mein Rückruf wird nur EINMAL für jedes erkannte BLE-Gerät aufgerufen. (Ich habe geseheninige Diskussion behaupten, dass dieses Verhalten von Gerät zu Gerät unterschiedlich sein kann) Ich interessiere mich jedoch für den sich ständig ändernden RSSI-Wert. Daher wird derzeit empfohlen, startLeScan und stopLeScan mit einem festgelegten Intervall (in meinem Fall 250 ms) fortlaufend auszuführen:

public class TheOldWay {

    private static final int SCAN_INTERVAL_MS = 250;

    private Handler scanHandler = new Handler();
    private boolean isScanning = false;

    public void beginScanning() {
        scanHandler.post(scanRunnable);
    }

    private Runnable scanRunnable = new Runnable() {
        @Override
        public void run() {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();

            if (isScanning) {
                adapter.stopLeScan(leScanCallback);
            } else if (!adapter.startLeScan(leScanCallback)) {
                // an error occurred during startLeScan
            }

            isScanning = !isScanning;

            scanHandler.postDelayed(this, SCAN_INTERVAL_MS);
        }
    };

    private BluetoothAdapter.LeScanCallback leScanCallback = new BluetoothAdapter.LeScanCallback() {
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            // use the RSSI value
        }
    };

}

Dies führt im Wesentlichen zu den erforderlichen Ergebnissen, ist jedoch sehr ressourcenintensiv und führt schließlich zu einem nicht reagierenden Bluetooth-Adapter.

Aus diesen Gründen habe ich mein Nexus 7 auf Android 5.0 Lollipop aktualisiert, um festzustellen, ob meine BLE-Probleme behoben sind. In Lollipop ist BluetoothAdapter.startLeScan (LeScanCallback) veraltet und wird durch @ ersetza neue API Dies ermöglicht eine bessere Kontrolle über den Scanvorgang. Bei meinen ersten Tests hat es den Anschein, dass startScan meinen Rückruf (auf meinem Nexus 7) nicht kontinuierlich aufruft, wenn sich die RSSI-Werte ändern, sodass ich weiterhin die startScan / stopScan-Implementierung verwenden muss:

@TargetApi(21)
public class TheNewWay {

    private static final int SCAN_INTERVAL_MS = 250;

    private Handler scanHandler = new Handler();
    private List<ScanFilter> scanFilters = new ArrayList<ScanFilter>();
    private ScanSettings scanSettings;
    private boolean isScanning = false;

    public void beginScanning() {
        ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
        scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
        scanSettings = scanSettingsBuilder.build();

        scanHandler.post(scanRunnable);
    }

    private Runnable scanRunnable = new Runnable() {
        @Override
        public void run() {
            BluetoothLeScanner scanner = BluetoothAdapter.getDefaultAdapter().getBluetoothLeScanner();

            if (isScanning) {
                scanner.stopScan(scanCallback);
            } else {
                scanner.startScan(scanFilters, scanSettings, scanCallback);
            }

            isScanning = !isScanning;

            scanHandler.postDelayed(this, SCAN_INTERVAL_MS);
        }
    };

    private ScanCallback scanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            super.onScanResult(callbackType, result);

            int rssi = result.getRssi();

            // do something with RSSI value
        }

        @Override
        public void onScanFailed(int errorCode) {
            super.onScanFailed(errorCode);

            // a scan error occurred
        }
    };

}

Wie Sie sehen, habe ich den Scanner mithilfe der ScanSettings-Klasse konfiguriert, mit der Sie das @ festlegen könnescanMode. Ich benutzeScanSettings.SCAN_MODE_LOW_LATENCY mit der folgenden Dokumentation: "Mit höchstem Arbeitszyklus scannen. Es wird empfohlen, diesen Modus nur zu verwenden, wenn die Anwendung im Vordergrund ausgeführt wird." Klingt genau so, wie ich es will, aber leider bekomme ich nur alle 15 - 30 Sekunden eine Beacon-Erkennung, wobei mir die KitKat-Version in diesem Suchintervall alle 1 - 2 Sekunden dieselbe Beacon anzeigt.

Haben Sie eine Idee, was der Grund für diesen Unterschied sein könnte? Vermisse ich etwas, vielleicht ein paar neue Einstellungen? Gibt es alternative Vorgehensweisen?

Vielen Dank im Voraus

Abel

PS: Ich wollte mehr Links zu Ressourcen einfügen, die ich verwendet habe, aber ich habe noch keine Wiederholungspunkte dafür.

Antworten auf die Frage(10)

Ihre Antwort auf die Frage