0

Ich arbeite an der Entfernungsschätzung von BLE Beacons vom Android-Handy. Ich habe meine eigenen Algorithmen zur Entfernungsschätzung basierend auf RSSI entwickelt. (Ich werde bald die Entfernungsberechnungsalgorithmen in Form einer Bibliothek ausrollen). Für Berechnungen benötigt Telefon eine große Anzahl von Werbepaketen von den Beacons herum.Infinite Android BLE Scan für BLE-Beacon-Pakete

Bis jetzt habe ich den Code mit normalen Praktiken für BLE-Scannen getestet. Ab sofort habe ich den Code für die Ziel-API Level 19 geschrieben. Nachfolgend ist ein Teil des Codes, an dem ich gerade arbeite, wo ich den Scan nach Beacons starte und nach 10s stoppe.

private void scanLeDevice(final boolean enable) { 
    if (enable) { 
     handler.postDelayed(new Runnable() { 
      @Override 
      public void run() { 
       bluetoothAdapter.stopLeScan(LEScanCallback); 
      } 
     }, 10000L); 

     bluetoothAdapter.startLeScan(LEScanCallback); 
    } 
} 
private BluetoothAdapter.LeScanCallback LEScanCallback = 
     new BluetoothAdapter.LeScanCallback() { 
      @Override 
      public void onLeScan(final BluetoothDevice bluetoothDevice, int rssi, byte[] scanRecord){ 
       display(rssi); 
       //append to an arrayList for further processing 
      } 
     }; 

Derzeit bin ich die meisten Dinge auf UI thread.I tun, um alle Funktionen in der folgenden Art und Weise zu erreichen, indem mehr Threads zu schaffen.

  1. UI Thread sollte frei von allen Berechnungen oder LeScans gehalten werden.
  2. PacketReaderThread - Ein separater Thread zum Scannen von Paketen und Anhängen sie an eine ArrayList (ich werde unnötige Daten von ArrayList wischen nach dem Verbrauch in Algorithmen). Anstatt den Scan nach einer bestimmten Zeit anzuhalten, möchte ich den Scan für unbegrenzte Zeit eingeschaltet lassen, um in Echtzeit weiterarbeiten zu können, sofern die App läuft. Also könnte ich IntentService dafür verwenden.
  3. DistanceCalculatorThread (oder AsyncTask) - ArrayList-Objekt (mit gescannten Paketen) wird zwischen diesem und dem PacketReaderThread zum Entnehmen/Löschen von Datenpaketen synchronisiert und über die Abstandsberechnung zur UI informiert.

sah ich die Implementierung von BluetoothAdapter.LeScanCallback auf Grepcode ich Fragen habe folgende.

  1. Ist BluetoothAdapter.LeScanCallback implizit gebunden/to main/UI-Thread gebunden oder ist es einem anderen Thread tragbar?
  2. Wenn ich beide Implementierungen des obigen Codes in einen anderen Thread verschiebe, wird der Callback an diesem Thread arbeiten oder wird er an den main/ui Thread gebunden? (Da ich Paket-Scannen auf separaten Thread brauche, muss ich wissen über BluetoothAdapter.startLeScan (LEScanCallback) und BluetoothAdapter.LeScanCallback)
    (Hinweis - Ich habe bereits gefolgt this question, in dieser Frage der Antwort-Sucher selbst besagt, dass Rückruf ist auf Hauptthread, so dass ich nicht die tatsächliche Antwort bekommen. auch altBeacon Spezifikationen und studierte ihre Referenz App, es nutzt auch CycledScan Mechanismus mit Scan-Stop-scanAgain Weg)

Antwort

1

Ja, die Android bluetooth ich sah Scan-Callbacks werden immer im Hauptthread ausgeführt. Dies gilt sowohl für die 4.x-APIs als auch für die 5+-APIs. Wenn Sie im Callback eine signifikante Verarbeitung mit Informationen durchführen, sollten Sie diese bei der Beschreibung an einen anderen Thread übergeben. Wenn Sie das nicht tun, wird die Benutzeroberfläche der App verzögert und die Bluetooth-Verarbeitung wird möglicherweise sogar gesichert und Sie werden Fehler in den Protokollen sehen.

Ich glaube nicht, dass dies offiziell überall dokumentiert ist, aber jahrelange Erfahrung mit diesen Rückrufen hat immer gezeigt, dass das wahr ist. Es gibt keine Möglichkeit, das Scannen so zu konfigurieren, dass die Rückrufe in einem anderen Thread stattfinden. Die beste Vorgehensweise besteht darin, einfach einen einzelnen Aufruf an einen anderen Thread zu senden, um die Verarbeitung durchzuführen und den Rückruf schnell zu beenden.

Dies ist, was in der Android Beacon Library wie gezeigt erfolgt here. Beachten Sie, dass der Körper des Callback verwendet einfach ein AsyncTask ein mit dieser Zeile auf einem Hintergrund-Thread ausgeführt wird:

new ScanProcessor(...).executeOnExecutor(mExecutor, 
        new ScanData(device, rssi, scanRecord)); 

Auch ist es wichtig, Beachten Sie, dass es zwar keinen Grund gibt, den Scan auf neueren Android-Geräten zu stoppen, auf einigen älteren Geräten erhalten Sie jedoch nur einen Callback pro eindeutiger Beacon-Mac-Adresse, wenn die Beacon-Werbung verbindbar ist. Die einzige Möglichkeit auf diesen Geräten ist es, den Scan zu stoppen und neu zu starten, um einen zusätzlichen Callback zu erhalten.

Viel Glück mit Ihrem Distanzalgorithmus - wenn Sie gute Ergebnisse haben und sich für die Android Beacon Library interessieren würden, würde ich gerne diskutieren.

+0

Ja, ich habe gute Ergebnisse. RSSI zum Distanzmapping konvergiert schneller als Locate;) Sie haben diese Bibliothek so gut geschrieben, ich habe sie studiert. Danke für die Antwort David, also werde ich LooperThread benutzen. Wenn Sie eine offizielle Dokumentation zu den Rückrufen finden, lassen Sie es bitte wissen. Und wir werden definitiv diskutieren, sobald ich die Demo in ein paar Wochen fertig habe. – Tejas