Обратный вызов Ble scan вызывает только несколько раз, а затем останавливается

У меня есть 2 телефона с Android 5.0.2, они оба установили последнее приложение Radius Beacon: Locate Beacon , между тем, я включил 2 отправителя IBeacon и вижу, что RSSI продолжает меняться в обоих телефонах с помощью приложения.

Но когда я попытался написать какой-то пример кода для симуляции выше ситуации, я обнаружил, что обратный вызов проверки всегда останавливается, вызывается после вызова 2 или 3 раза , изначально я подозреваю, что «Locate Beacon» может использоваться по-другому, поэтому я попробовал с 2-мя видами API, один для старых 4.4, а другой – новый способ, введенный в android 5, но и то же поведение (но все работает на android 5).

4.4:

public class MainActivity extends Activity { private BluetoothAdapter mBluetoothAdapter; private static final String LOG_TAG = "BleCollector"; private TextView calledTimesTextView = null; private int calledTimes = 0; // Device scan callback. private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() { @Override public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) { calledTimes++; runOnUiThread(new Runnable() { @Override public void run() { calledTimesTextView.setText(Integer.toString(calledTimes)); } }); Log.e(LOG_TAG, "in onScanResult, " + " is coming..."); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); calledTimesTextView = (TextView) findViewById(R.id.CalledTimes); mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE)) .getAdapter(); mBluetoothAdapter.startLeScan(mLeScanCallback); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); }} 

И 5.0.2:

 public class MainActivity extends Activity { private BluetoothAdapter mBluetoothAdapter = null; private BluetoothLeScanner mLescanner; private ScanCallback mLeScanCallback; private static final String LOG_TAG = "BleFingerprintCollector"; private TextView calledTimesTextView = null; private int calledTimes = 0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); calledTimesTextView = (TextView) findViewById(R.id.CalledTimes); this.mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE)) .getAdapter(); this.mLescanner = this.mBluetoothAdapter.getBluetoothLeScanner(); ScanSettings bleScanSettings = new ScanSettings.Builder().setScanMode( ScanSettings.SCAN_MODE_LOW_LATENCY).build(); this.mLeScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { calledTimes++; runOnUiThread(new Runnable() { @Override public void run() { calledTimesTextView.setText(Integer .toString(calledTimes)); } }); Log.e(LOG_TAG, "in onScanResult, " + " is coming..."); } @Override public void onBatchScanResults(List<ScanResult> results) { } @Override public void onScanFailed(int errorCode) { } }; this.mLescanner.startScan(null, bleScanSettings, this.mLeScanCallback); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); }} 

Они очень просты и просто показывают счетчик в пользовательском интерфейсе, который, наконец, всегда останавливался на 2 или 3.

Я сыграл этот рекламный прием, прежде чем на заметке 2 SamSung с устройством Android 4.4, он отлично работает, callback вызывается каждую секунду. То кто-нибудь может помочь? Почему Radius Locate Beacon хорошо работает здесь ?

Solutions Collecting From Web of "Обратный вызов Ble scan вызывает только несколько раз, а затем останавливается"

Различные устройства Android ведут себя по-разному при сканировании подключаемых рекламных объявлений BLE. На некоторых устройствах (например, Nexus 4) API-интерфейсы сканирования получают только один обратный вызов для сканирования передатчиков, отправляющих подключаемую рекламу, тогда как они получают обратный вызов сканирования для каждого объявления для несанкционированных рекламных объявлений. Другие устройства (например, Nexus 5) обеспечивают обратный вызов сканирования для каждого отдельного объявления независимо от того, подключено ли оно.

В приложении Locate вы используете библиотеку Beacon с открытым исходным кодом для обнаружения маяков. Он построен поверх тех же API-интерфейсов сканирования, которые вы показываете в своем вопросе, но он оборачивается этой проблемой, определяя период сканирования (по умолчанию на 1.1 секунды по умолчанию) и останавливая и перезапуская сканирование с этого интервала. Прекращение и перезапуск сканирования заставляет Android отправлять новый обратный вызов.

Несколько примечаний здесь:

  • Эта проблема получения нескольких обратных вызовов сканирования для подключаемых устройств применяется как к API-интерфейсам сканирования 4.x, так и 5.x.

  • Неясно, зависит ли разница в доставке обратных вызовов сканирования для подключаемых рекламных объявлений на разных устройствах из-за различий в прошивке Android или различий в чипсете Bluetooth.

  • Кажется, что не существует способа определить, требует ли устройство перезапуска сканирования, чтобы получить дополнительные обратные вызовы для подключаемых рекламных объявлений, поэтому, если вы настраиваете таргетинг на самые разные устройства, вам нужно планировать остановку и повторное сканирование.

  • Использование необработанных API сканирования Android – отличный способ понять, как работают маяки BLE. Но есть много сложностей с работой с маяками BLE (это всего лишь один пример), поэтому использование SDK, такого как Android Beacon Library, является хорошим выбором, чтобы вы не вытягивали свои волосы.

Полное раскрытие: я являюсь автором приложения Locate в ведущем разработчике проекта Android Beacon Library с открытым исходным кодом.

Дэвид – Вы уверены, что вызов вызова сканирования вызван для каждой рекламы, не подлежащей подключению. У меня есть Xiaomi Redmi 3 и еще один телефон Nexus 5 с Android 6.0. У меня есть датчик BLE, который через каждые 1 минуту передает данные. Эти телефоны, появляющиеся в качестве центрального устройства BLE, должны получать и обрабатывать данные с датчика. Я вижу из устройства захвата BLE Over the Air (OTA), которое датчик передает данные каждые 1 минуту. Однако оба телефона, по-видимому, обрабатывают данные в течение нескольких минут с интервалом в 1 минуту, но после этого прекращают обработку в течение 4-6 минут, а затем начинают обработку ag, enter code here . Временной интервал обработки телефона выглядит следующим образом: 1 мин, 2 мин, 3 мин, 8 мин, 9 мин, 10 мин, 11 мин. После обработки 3 пакетов с интервалом в 1 минуту либо телефон прекратит обработку в течение 4-6 минут.

Вот код, который обрабатывает.

 public class BluetoothDataReader { private final Context context; public BluetoothDataReader(Context context) { this.context = context; } public void startReading() { BluetoothAdapter btAdapter = getBluetoothAdapter(); if (btAdapter == null) return; BluetoothLeScanner scanner = btAdapter.getBluetoothLeScanner(); ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY) .build(); scanner.startScan(Collections.<ScanFilter>emptyList(), settings, new ScanRecordReader()); } public void uploadScanBytes(SensorDataUploader sensorDataUploader, int count) { BluetoothAdapter btAdapter = getBluetoothAdapter(); if (btAdapter == null) return; BluetoothLeScanner scanner = btAdapter.getBluetoothLeScanner(); ScanSettings settings = new ScanSettings.Builder() .setScanMode(ScanSettings.SCAN_MODE_BALANCED) .setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES) .build(); // scanner.startScan(Arrays.asList(new ScanFilter.Builder().setDeviceAddress("26:50:26:50:26:50").build()), settings, new LimitedScanRecordReader(sensorDataUploader, count, scanner)); scanner.startScan(Collections.<ScanFilter>emptyList(), settings, new LimitedScanRecordReader(sensorDataUploader, count, scanner)); } @Nullable private BluetoothAdapter getBluetoothAdapter() { BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter(); if(btAdapter == null){ Log.i(BluetoothDataReader.class.getName(), "No bluetooth adapter available"); return null; } if(!btAdapter.isEnabled()){ Log.i(BluetoothDataReader.class.getName(), "Enable bluetooth adapter"); Intent enableBluetooth = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); context.startActivity(enableBluetooth); } return btAdapter; } private class LimitedScanRecordReader extends ScanCallback { private final int limit; private final BluetoothLeScanner scanner; private int scanRecordRead = 0; private final SensorDataUploader sensorDataUploader; private LimitedScanRecordReader( SensorDataUploader sensorDataUploader, int limit, BluetoothLeScanner scanner) { this.limit = limit; this.scanner = scanner; this.sensorDataUploader = sensorDataUploader; } @Override public void onScanResult(int callbackType, ScanResult result) { // if(scanRecordRead++ < limit) { // if(result.getDevice().getAddress().equals("A0:E6:F8:01:02:03")) { // if(result.getDevice().getAddress().equals("C0:97:27:2B:74:D5")) { if(result.getDevice().getAddress().equals("A0:E6:F8:01:02:03")) { long timestamp = System.currentTimeMillis() - SystemClock.elapsedRealtime() + result.getTimestampNanos() / 1000000; byte[] rawBytes = result.getScanRecord().getBytes(); Log.i(DataTransferService.class.getName(), "Raw bytes: " + byteArrayToHex(rawBytes)); sensorDataUploader.upload(timestamp, rawBytes); } // }else { // scanner.stopScan(this); // } } public String byteArrayToHex(byte[] a) { StringBuilder sb = new StringBuilder(a.length * 2); for(byte b: a) sb.append(String.format("%02x", b & 0xff)); return sb.toString(); } public void onScanFailed(int errorCode) { Log.i(DataTransferService.class.getName(), "Error code is:" + errorCode); } public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult> results) { Log.i(DataTransferService.class.getName(), "Batch scan results"); } } private class ScanRecordReader extends ScanCallback { @Override public void onScanResult(int callbackType, ScanResult result) { byte []rawBytes = result.getScanRecord().getBytes(); Log.i(DataTransferService.class.getName(), "Raw bytes: " + byteArrayToHex(rawBytes )); // Map<ParcelUuid, byte[]> serviceData = result.getScanRecord().getServiceData(); // for(ParcelUuid uuid : serviceData.keySet()) { // Log.i(DataTransferService.class.getName(), uuid.toString() + ":" + byteArrayToHex(serviceData.get(uuid))); // } // Log.i(DataTransferService.class.getName(),result.toString()); } public String byteArrayToHex(byte[] a) { StringBuilder sb = new StringBuilder(a.length * 2); for(byte b: a) sb.append(String.format("%02x", b & 0xff)); return sb.toString(); } public void onScanFailed(int errorCode) { Log.i(DataTransferService.class.getName(), "Error code is:" + errorCode); } public void onBatchScanResults(java.util.List<android.bluetooth.le.ScanResult> results) { Log.i(DataTransferService.class.getName(), "Batch scan results"); } } }