android - 其他应用程序使我的 Android 应用程序的 BLE 扫描非常慢
问题描述
自从我相信 Nougat 以来,我的应用程序的 BLE 扫描性能似乎逐渐减慢。我现在可以回去在 Marshmallow 上进行测试,并确定那里不存在问题,但我在 Nougat 上没有设备了。我在 Pie 上的 Pixel 3a 严重显示了这个问题。
问题
当我的应用程序正在执行 BLE 扫描并且我正在寻找的设备就在我面前时,通常需要 30 - 60 秒,有时甚至更长时间,LE 扫描才会在 ScanCallback 中返回该设备。我的扫描代码非常简单:
private synchronized void startScan(@Nonnull BluetoothAdapter adapter, UUID[] serviceUuids) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
if (serviceUuids != null && serviceUuids.length > 0) {
adapter.startLeScan(serviceUuids, BleScannerService.this);
} else {
adapter.startLeScan(BleScannerService.this);
}
broadcastUpdate(ACTION_SCAN_STARTED);
} else {
List<ScanFilter> filters = new ArrayList<>();
if (serviceUuids != null && serviceUuids.length > 0) {
for (UUID uuid : serviceUuids) {
filters.add(new ScanFilter.Builder().setServiceUuid(new ParcelUuid(uuid))
.build());
}
}
BluetoothLeScanner scanner = adapter.getBluetoothLeScanner();
if (scanner != null) {
ScanSettings.Builder builder = new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setReportDelay(0);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
builder.setMatchMode(ScanSettings.MATCH_MODE_AGGRESSIVE);
}
adapter.getBluetoothLeScanner().startScan(filters,
builder.build(),
mScanCallback);
broadcastUpdate(ACTION_SCAN_STARTED);
} else {
mScanning = false;
}
}
}
该代码的很大一部分是指定已经是默认值的 ScanSettings,但我无能为力地尝试所有方法。所以我花了几天调试,终于在 logcat 中发现了一个非常有趣的模式。
每次在 ScanCallback 中找到设备时,我都会输出一个日志。当我的扫描第一次开始时,它只会每隔一两秒得到一个结果。我什至看到扫描结果之间需要 10 秒。正是在这段时间里,我的 BLE 设备没有被发现,大概是因为手机使用的任何巨大的扫描间隔都没有与 BLE 设备的广播间隔对齐。
然而,在某些时候它刚刚打开,我开始每秒得到很多结果,我的 BLE 设备马上就被找到了。我最终每次都在闸门打开的那一刻找到了这些日志(这是在派上):
2019-08-16 09:13:17.813 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 88:6B:0F:64:2F:D7
2019-08-16 09:13:28.087 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 88:6B:0F:64:2F:D7
2019-08-16 09:13:30.582 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 6F:23:65:B7:D9:43
2019-08-16 09:13:33.024 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 00:07:80:CF:17:B9
2019-08-16 09:13:33.357 23338-23338/? D/BluetoothGatt: close()
2019-08-16 09:13:33.357 23338-23338/? D/BluetoothGatt: unregisterApp() - mClientIf=7
2019-08-16 09:13:33.363 23338-23338/? D/BluetoothManager: getConnectionState()
2019-08-16 09:13:33.363 23338-23338/? D/BluetoothManager: getConnectedDevices
2019-08-16 09:13:33.407 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 6F:90:AC:1D:EF:38
2019-08-16 09:13:33.491 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 6F:23:65:B7:D9:43
2019-08-16 09:13:33.524 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned F4:5C:89:90:C6:24
2019-08-16 09:13:33.625 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 46:54:BD:32:A2:EF
2019-08-16 09:13:33.708 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned F4:5C:89:90:C6:24
2019-08-16 09:13:34.374 23338-23338/? D/BluetoothGatt: connect() - device: C5:8B:66:21:90:5B, auto: true
2019-08-16 09:13:34.374 23338-23338/? D/BluetoothGatt: registerApp()
2019-08-16 09:13:34.374 23338-23338/? D/BluetoothGatt: registerApp() - UUID=35e43611-6c73-47a6-ad0d-9919df01108f
2019-08-16 09:13:34.378 23338-23480/? D/BluetoothGatt: onClientRegistered() - status=0 clientIf=7
2019-08-16 09:13:34.408 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 6F:23:65:B7:D9:43
2019-08-16 09:13:34.424 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned F4:5C:89:90:C6:24
2019-08-16 09:13:34.492 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 6F:90:AC:1D:EF:38
2019-08-16 09:13:34.592 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 6F:23:65:B7:D9:43
2019-08-16 09:13:34.608 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned F4:5C:89:90:C6:24
2019-08-16 09:13:34.658 27109-27109/<my package> E/<my app>: BleScannerService.java:275 onLeScan(): WPW: scanned 46:54:BD:32:A2:EF
所以 close() 完成的那一刻就是闸门打开的时候。还有一些其他应用程序持有 gatt 试图连接到某些东西,而当这种情况发生时,我的应用程序的扫描速度非常慢(也许 Android 会自动将其转换为 SCAN_MODE_OPPORTUNISTIC 或 SCAN_MODE_LOW_POWER 忽略我的 SCAN_MODE_LOW_LATENCY?)。
另一个始终存在的日志是“connect() - device: C5:8B:66:21:90:5B, auto: true”。我很幸运,能够在我手机的蓝牙设置中找到 C5:8B:66:21:90:5B……这是我的 Garmin GPS 手表!
原因
看起来,当我的手表关闭蓝牙或超出范围时,Garmin Connect 应用程序一直在扫描它(嗯,尝试使用自动标志连接),这就是导致我的 BLE 扫描非常缓慢地返回结果的原因。一旦连接超时,我的 BLE 扫描就会尖叫…… Garmin Connect 在我的 BLE 扫描期间会进行另一次连接,但我想现在我的扫描需要优先级并且它会一直保持很快,直到我取消它并重新开始它。然后它很慢,直到 Garmin 的连接再次超时。
我通过几种方式确认这是问题所在:
- 我卸载了 Garmin Connect。我的应用程序运行良好,每次都快速扫描。
- 我打开手表的蓝牙,让手机连接到它(因此不再试图找到它)。我的应用程序运行良好,每次都快速扫描。
回到 Marshmallow 上的手机,即使安装了 Garmin Connect 但手表未连接,上述问题也根本不会发生。我的假设是 Android 中发生了一些变化,导致一个应用程序的 connect() 干扰了另一个应用程序的 startScan()。在 Marshmallow 他们不会互相干扰,在 Pie 他们会。我猜它是从牛轧糖开始的,基于我读过的很多其他东西,但我无法证实。
有解决方案吗?
我不知道,但我希望有人在那里。据我所知,真的没有办法让你的应用程序“接管”蓝牙适配器或试图强迫自己比使用它的任何其他应用程序拥有资历(可以理解)。
有没有办法进行 BLE 扫描,以便它立即进入低延迟状态,而不管手机上发生了什么?它当然在棉花糖中起作用......
解决方案
推荐阅读
- jquery - 具有值更改的从属选择并在更改时禁用 attr
- android - Android后台定位服务有时会停止
- github - Github Actions 发布到其他仓库
- android - Ubuntu 20.04 android studio 启动慢?
- python - 如何在数据框中大写首字母缩写词
- node.js - 如何分隔有和没有查询参数的路线?
- javascript - react-file-viewer 使任何文件都非常小
- google-cloud-platform - 计算引擎 Debian 中的错误 GTK 警告
- wordpress - Dokan 供应商向每个供应商添加简码
- javascript - 为什么带有 async/await 的 axios 在这种情况下不起作用?