精简版:
在我对 Android 5.0 Lollipop 的测试中,我注意到android.bluetooth.le.BluetoothLeScanner
检测 BLE 设备的频率低于 Android 4.4 KitKat。为什么会这样,还有其他选择吗?
长版:
我正在开发一个 Android 应用程序,专门用于 Nexus 7 平板电脑,专注于检测蓝牙低功耗 (BLE) 设备。该应用程序主要对信标的 RSSI 值感兴趣,以确定它们与平板电脑的接近程度。这意味着我不需要连接到 BLE 设备,因为当检测到设备时,RSSI 值会传递给扫描回调。
在 Android 4.4 KitKat 中,当我调用时BluetoothAdapter.startLeScan(LeScanCallback)
,我的回调只会为每个检测到的 BLE 设备调用一次。(我已经看到一些讨论声称这种行为可能因设备而异)但是,我对不断变化的 RSSI 值感兴趣,因此目前推荐的方法是以设定的间隔(在我的情况下为 250 毫秒)连续执行 startLeScan 和 stopLeScan:
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
}
};
}
本质上,这给了我所需的结果,但这个过程非常耗费资源,并最终导致蓝牙适配器无响应。
由于这些原因,我将我的 Nexus 7 升级到了 Android 5.0 Lollipop,看看我的 BLE 问题是否会得到修复。在 Lollipop 中,BluetoothAdapter.startLeScan(LeScanCallback) 已被弃用,取而代之的是允许对扫描过程进行更多控制的新 API 。从我的第一次测试来看,当 RSSI 值发生变化时,startScan 似乎不会连续调用我的回调(在我的 Nexus 7 上),所以我仍然需要使用 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:我想包含更多指向我使用过的资源的链接,但我还没有代表点。