Ble扫描回调只被调用几次然后停止

Sha*_*awn 9 android bluetooth-lowenergy indoor-positioning-system ibeacon

我有两部搭载Android 5.0.2的手机,它们都安装了最新的Radius Beacon应用程序:Locate Beacon,同时,我打开了2个IBeacon发送器,可以看到RSSI 在两款手机中随着应用程序不断变化.

但是当我尝试编写一些示例代码来模拟上述情况时,我发现ble扫描回调总是在调用2或3次后停止调用,我最初怀疑'Locate Beacon'可能使用不同的方式,所以我尝试了2种API,一个用于旧的4.4,另一个是在android 5中引入的新方式,但两者都是相同的行为(但都在android 5上运行).

4.4一:

public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter;
private static final String LOG_TAG = "BleCollector";
private TextView calledTimesTextView = null;
private int calledTimes = 0;
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi,
            byte[] scanRecord) {
        calledTimes++;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {

                calledTimesTextView.setText(Integer.toString(calledTimes));
            }
        });
        Log.e(LOG_TAG, "in onScanResult, " + " is coming...");
    }
};

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    calledTimesTextView = (TextView) findViewById(R.id.CalledTimes);
    mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE))
            .getAdapter();
    mBluetoothAdapter.startLeScan(mLeScanCallback);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}}
Run Code Online (Sandbox Code Playgroud)

而5.0.2:

public class MainActivity extends Activity {
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothLeScanner mLescanner;
private ScanCallback mLeScanCallback;
private static final String LOG_TAG = "BleFingerprintCollector";
private TextView calledTimesTextView = null;
private int calledTimes = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    calledTimesTextView = (TextView) findViewById(R.id.CalledTimes);
    this.mBluetoothAdapter = ((BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE))
            .getAdapter();
    this.mLescanner = this.mBluetoothAdapter.getBluetoothLeScanner();

    ScanSettings bleScanSettings = new ScanSettings.Builder().setScanMode(
            ScanSettings.SCAN_MODE_LOW_LATENCY).build();

    this.mLeScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            calledTimes++;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {

                    calledTimesTextView.setText(Integer
                            .toString(calledTimes));
                }
            });
            Log.e(LOG_TAG, "in onScanResult, " + " is coming...");
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {

        }

        @Override
        public void onScanFailed(int errorCode) {
        }
    };
    this.mLescanner.startScan(null, bleScanSettings, this.mLeScanCallback);

}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle action bar item clicks here. The action bar will
    // automatically handle clicks on the Home/Up button, so long
    // as you specify a parent activity in AndroidManifest.xml.
    int id = item.getItemId();
    if (id == R.id.action_settings) {
        return true;
    }
    return super.onOptionsItemSelected(item);
}}
Run Code Online (Sandbox Code Playgroud)

它们非常简单,只是在UI中显示一个计数器,最终证明它总是停在2或3.

我之前在使用android 4.4设备的SamSung笔记2上播放了这个广告,它运行得很好,每秒都会调用回调.那么有人可以帮忙吗?为什么Radius'Locate Beacon在这里工作得很好

dav*_*ung 19

扫描可连接的 BLE广告时,不同的Android设备的行为会有所不同. 在某些设备(例如Nexus 4)上,扫描API仅针对发送可连接广告的发送器每次扫描获得一次回调,而针对不可连接广告的每个广告获得扫描回调.其他设备(例如Nexus 5)提供每个广告的扫描回调,无论它是否可连接.

您提到的Locate应用程序使用开源Android Beacon Library来检测信标.它建立在您在问题中显示的相同扫描API之上,但它通过定义扫描周期(前景中默认为1.1秒)并以此间隔停止并重新启动扫描来解决此问题. 停止并重新启动扫描会导致Android发送新的回调.

其他一些注意事项:

  • 为可连接设备获取多个扫描回调的问题适用于4.x和5.x扫描API.

  • 目前尚不清楚在不同设备上为可连接广告提供扫描回调的差异是由于Android固件差异还是蓝牙硬件芯片组差异造成的.

  • 似乎没有办法检测设备是否需要重新启动扫描才能获得可连接广告的额外回调,因此如果您要定位各种设备,则需要计划停止并重新开始扫描.

  • 使用Android的原始扫描API是理解BLE信标如何工作的好方法.但是使用BLE信标有很多复杂的问题(这只是一个例子),这就是为什么使用像Android Beacon Library这样的SDK是一个很好的选择,可以防止你脱头而出.

完全披露:我是Android Beacon Library开源项目的首席开发人员中的Locate应用程序的作者.