在Android 5.0 Lollipop上减少了BLE startScan检测到的设备

时间:2014-11-24 18:05:54

标签: bluetooth-lowenergy android-5.0-lollipop rssi ibeacon-android android-ibeacon

简短版本:

在我使用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设备被调用ONCE。 (我已经看到some discussions声称每个设备的行为可能不同)但是,我对不断变化的RSSI值感兴趣,所以目前推荐的方法是连续执行startLeScan和stopLeScan,设置间隔(我的250ms)情况下):

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)并将其替换为a new 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,其中包含以下文档:&#34;使用最高占空比扫描。建议仅在应用程序在前台运行时才使用此模式。&#34;听起来和我想要的完全一样,但遗憾的是我每15到30秒才会检测到一个信标,其中KitKat版本在此扫描间隔内每隔1-2秒向我显示相同的信标。

您是否知道造成这种差异的原因是什么?我错过了什么,也许是一些新的设置?有其他方法可以做到吗?

提前多多感谢!

阿贝尔

PS:我想要包含更多我已经使用的资源的链接,但我还没有获得它的代表点。

5 个答案:

答案 0 :(得分:6)

使用运行新Android 5.0扫描API的Nexus 5,我得到了非常不同的结果。当使用SCAN_MODE_LOW_LATENCY时,BLE数据包的检测几乎是实时的,每100ms用于以10Hz发送的BLE信标。

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

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

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

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

编辑:硬件可能与众不同。请参阅Nexus 4上类似时间的报告:https://github.com/AltBeacon/android-beacon-library/issues/59#issuecomment-64281446

答案 1 :(得分:5)

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

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

改为:

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

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

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

答案 2 :(得分:2)

在KitKat和Lollipop中,我的Nexus 4经历了非常相似的结果。

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

现在有了Lollipop,我很有希望解决这个问题,我经历了你所描述的相同行为。我还必须使用startScan / stopScan实现,获得有关检测时间的类似结果。可悲的是,我还没有找到更快速获得结果的工作。

基于您所描述的内容,我认为它可能是硬件问题,即使Nexus 7和Nexus 4来自不同的制造商(华硕和LG)。

我知道除了试图回答你关于你遗失某些事情的问题之外,我在这方面没有提供太多帮助;我不这么认为,我认为这个问题类似于硬件或蓝牙API,它仍然不会像在不同设备上那样运行。

答案 3 :(得分:1)

Beyond API 21 android默认使用 SCAN_MODE_LOW_POWER SCAN_MODE_LOW_POWER

尝试SCAN_MODE_BALANCED并查看它是否变得更好 SCAN_MODE_BALANCED

答案 4 :(得分:0)

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

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