Краткая версия:
В моих тестах с Android 5.0 Lollipop я заметил android.bluetooth.le.BluetoothLeScanner
обнаруживает устройства BLE менее часто, чем Android 4.4 KitKat. Почему это и есть альтернатива?
Длинная версия:
Я разрабатываю приложение для Android, особенно для планшета Nexus 7, которое фокусируется на обнаружении устройств с низкой энергией Bluetooth (BLE). Приложение в основном интересуется значением RSSI маяков, чтобы определить их близость к планшету. Это означает, что мне не нужно будет подключаться к устройству BLE, поскольку значение RSSI передается на обратный вызов сканирования при обнаружении устройства.
В Android 4.4 KitKat, когда я вызываю BluetoothAdapter.startLeScan(LeScanCallback)
, мой callback вызывается только ONCE для каждого обнаруженного устройства BLE. (Я видел некоторые обсуждения утверждают, что это поведение может различаться для каждого устройства). Тем не менее, меня интересует постоянно меняющееся значение RSSI, поэтому в настоящее время рекомендуется постоянно делать startLeScan и stopLeScan с заданным интервалом (250 мс в моем случае):
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
}
};
}
По сути, это дает мне необходимые результаты, но этот процесс очень ресурсоемкий и в конечном итоге приводит к невосприимчивому адаптеру Bluetooth.
По этим причинам я обновил свой Nexus 7 до Android 5.0 Lollipop, чтобы проверить, будут ли исправлены мои проблемы с BLE. В Lollipop BluetoothAdapter.startLeScan(LeScanCallback) устарел и заменен на новый API, который позволяет контролировать некоторые процессы сканирования. Из моих первых тестов появляется, что startScan постоянно вызывает мой обратный вызов (на моем Nexus 7), когда значения RSSI меняются, поэтому мне все равно нужно использовать реализацию startScan/stopScan:
@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
}
};
}
Как вы можете видеть, я настроил сканер с помощью класса ScanSettings, который позволяет вам установить scanMode
. Я использую ScanSettings.SCAN_MODE_LOW_LATENCY
, который имеет следующую документацию: "Сканирование с использованием максимального рабочего цикла. Рекомендуется использовать этот режим только в том случае, если приложение работает на переднем плане". Звучит точно так, как я хочу, но, к сожалению, я получаю маяк только каждые 15-30 секунд, где версия KitKat показывает мне тот же маяк каждые 1 - 2 секунды в этом интервале сканирования.
Есть ли у вас какая-то идея, что может быть причиной этой разницы? Я что-то упустил, может быть, некоторые новые настройки? Существуют ли альтернативные способы выполнения вышеуказанного?
Большое спасибо!
Абель
PS: Я хотел добавить больше ссылок на ресурсы, которые я использовал, но у меня пока нет репутационных баллов.