降低 BLE 启动扫描检测到的设备 Android 5.0 棒棒糖.



简短版本:

在我对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值感兴趣,因此目前推荐的方法是连续执行startLeScan并以设定的间隔(在我的情况下为250ms)停止LeScan:

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棒棒糖,看看我的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:我想包含更多指向我使用过的资源的链接,但我还没有代表点。

我在运行新的Android 5.0扫描API的Nexus 5上得到了非常不同的结果。 使用SCAN_MODE_LOW_LATENCY时,BLE数据包的检测近乎实时,对于以10Hz传输的BLE信标,每100ms一次。

您可以在此处阅读完整结果:

http://developer.radiusnetworks.com/2014/10/28/android-5.0-scanning.html

这些测试基于运行开源Android Beacon Library 2.0的实验性android-l-apis分支。

测试结果的差异并不明显,但开始和停止扫描可能会改变结果。

编辑:硬件可能是区别。 在Nexus 4上查看类似时间的报告:https://github.com/AltBeacon/android-beacon-library/issues/59#issuecomment-64281446<</p>

div class="one_answers">

我还没有 50 个评论的声誉,所以请耐心等待,此评论将以答案的形式出现。在你的代码中,这部分不应该:

if (isScanning) { scanner.startScan(...)

改为:

if (!isScanning) {
 scanner.startScan(...)

因为按照您的代码,您在开始扫描之前调用 stopScan()。如果 stopScan() 方法是幂等/安全的,则可能不会对结果产生直接影响。但是你知道,为了代码的可理解性,你应该编辑这个问题。并对你的代码做同样的事情,有时拜占庭式的东西在起作用;)

您是否尝试过更大的SCAN_INTERVAL_MS值?如果是,有多大?

我在Nexus 4上都经历了非常相似的结果,无论是KitKat还是Lollipop。

使用KitKat,蓝牙适配器最终也无响应; 起初,我认为它可能与较短的扫描间隔(200ms)有关,但是将该数字增加到甚至一秒钟也无济于事,在这种情况下,我发现,当无响应时,以编程方式禁用和启用适配器,有时可以解决问题。不幸的是,我不能说它一直有效。

现在有了棒棒糖,我对解决这个问题寄予厚望,我经历了你描述的同样的行为。我还必须使用startScan/stopScan实现,在检测时间方面获得类似的结果。可悲的是,我还没有找到可以更快地获得结果的解决方法。

根据您的描述,我认为这可能是硬件问题,即使Nexus 7和Nexus 4来自不同的制造商(华硕和LG)。

我知道除了试图回答你关于你错过某些东西的问题之外,我在这里没有提供太多帮助;我不这么认为,我认为问题在于硬件或蓝牙 API 在不同设备上的行为方式仍然不尽如人意。

Beyond API 21 Android 默认使用SCAN_MODE_LOW_POWER。SCAN_MODE_LOW_POWER

尝试SCAN_MODE_BALANCED,看看它是否会变得更好。
SCAN_MODE_BALANCED

如果您在Google上搜索BW13_DayOne_Session1 Bluetooth Advanced,您会发现一个PDF文档,该文档根据发现设置为您提供设备的延迟(请参阅第8页)。我猜你的问题与这些时间有关。您可以通过确定要测试的设备的广告配置(Adv Int、占空比)进行验证,然后确定 API 设置在配置扫描间隔等方面的作用。获得这些后,您可以使用该表进行插值,以查看是否获得了预期的结果。

我知道这是一个软件站点,但通常与硬件接口时,您需要知道协议,否则您将在黑暗中拍摄。

最新更新