![](https://i-blog.csdnimg.cn/blog_migrate/e2d18c59acab5c9d3bc94a9b2e4a4ba4.png)
前言
随着BLE蓝牙技术的发展,利用蓝牙进行数据信息交互变得越来越常见。但是Android的蓝牙扫描默认只是一次性的短时间扫描。为了实现持续扫描的效果,我们需要自定义扫描逻辑。
蓝牙是一种让设备在短距离内进行无线通信的技术。在Android系统上,我们可以通过蓝牙API以编程方式扫描附近的蓝牙设备。
默认情况下,蓝牙扫描只会执行一次并返回发现的设备列表。但是,我们通常需要持续一段时间扫描蓝牙设备。这样可以检测到初始扫描时可能关闭或不在范围内的设备。
![](https://i-blog.csdnimg.cn/blog_migrate/7bb5c76128e69a68cc6e081360ca4337.gif)
那么我们该如何实现蓝牙持续扫描的方法呢?接下来让我们一起来看看吧!
最近项目开发中,对于蓝牙血糖仪测量模块在实际应用中,需要让蓝牙持续扫描,根据mac地址可以指定连接到设备之后,进行测量等其他操作。
项目中应用的低功耗蓝牙血糖仪,这里和大家提一嘴。不论传统蓝牙,还是低功耗的,其实对于持续扫描蓝牙这个功能,根据不同的用户场景处理都是一样的。
持续蓝牙扫描
持续蓝牙扫描意思是:
让蓝牙一直处于扫描状态,需要注意的是扫描会消耗更多电量,可以根据需要适当调整扫码周期。
1、 通过注册BroadcastReceiver的形式来监听蓝牙扫描状态。
2、 为了让扫描一直持续,可以在一个后台Service里进行扫描,并不断调用startLeScan()重新启动扫描。另外可以在扫描到设备后继续扫描而不是停止。
3、 在一个while(true)循环里持续调用startLeScan()重新扫描, 获取到扫描结果后可以选择连接或过滤处理。
实际应用
这里举例两种形式
,来实现蓝牙持续扫描功能。
方式一: 通过注册BroadcastReceiver的形式来实现此功能。
- 定义BroadcastReceiver用于接收扫描结果
private BroadcastReceiver scanReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
// 获取扫描到的设备并处理
}
};
- 在onCreate中初始化
BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(scanReceiver, filter);
- 开一个线程持续扫描
new Thread(new Runnable() {
@Override
public void run() {
while(true) {
adapter.startLeScan(leScanCallback);
try {
Thread.sleep(10000); // 间隔10秒后继续扫描
} catch (InterruptedException e) {
e.printStackTrace();
}
adapter.stopLeScan(leScanCallback);
}
}
}).start();
- 在onDestroy中注销receiver
@Override
protected void onDestroy() {
unregisterReceiver(scanReceiver);
super.onDestroy();
}
方式二: 在一个while(true)循环里持续调用startLeScan()重新扫描, 获取到扫描结果后可以选择连接或过滤处理。
在开一个线程持续扫描蓝牙的情况下,如果想在退出Activity时停止扫描线程,可以通过如下几种方式:
- 设置一个标志位来控制线程的运行状态:
private boolean scanning = true;
// 在线程中
while(scanning) {
// 扫描逻辑
}
// 在onDestroy中
scanning = false;
- 使用线程的interrupt()方法中断线程:
Thread scanThread;
// 在onCreate中
scanThread = new Thread() {
@Override
public void run() {
while(true) {
// 扫描逻辑
}
}
};
scanThread.start();
// 在onDestroy中
scanThread.interrupt();
- 使用Handler发消息通知线程停止:
Handler handler;
// 在线程中
public void run() {
while(true) {
if(handler.hasMessages(MSG_STOP)) {
break;
}
// 扫描逻辑
}
}
// 在onDestroy中
handler.sendEmptyMessage(MSG_STOP);
- 使用ExecutorService执行线程,在onDestroy中调用shutdownNow():
ExecutorService executor = Executors.newSingleThreadExecutor();
executor.execute(scanTask);
// 在onDestroy中
executor.shutdownNow();
- 在扫描循环加入退出条件:
boolean stop = false;
while(!stop) {
// 扫描逻辑
}
// 在onDestroy中
stop = true;
对于如上第二种方式中,我自己应用的是(1)中的形式,
设置一个标志位来控制线程的运行状态,具体执行如下:
private boolean scanning = true;
// 开启一个线程
new Thread(new Runnable() {
@Override
public void run() {
while (scanning) {
initBle();
LogUtils.e("开始执行扫描handler >>>", "startScan");
try {
Thread.sleep(10000); // 间隔10秒后继续扫描
} catch (InterruptedException e) {
e.printStackTrace();
}
BleManager.getInstance().cancelScan();
LogUtils.e("开始执行扫描handler >>>", "取消扫描");
}
}
}).start();
// 在onDestroy中
@Override
protected void onDestroy() {
scanning = false;
super.onDestroy();
}
最后
到这里,实现蓝牙持续扫描的功能,就已经完成了,欢迎各位质检,点击关注❤️,留言探讨!
这里有一个重点,有的开辟线程之后,没有关闭扫描,每隔10秒都会执行扫描
。每当退出蓝牙连接界面后,它会一直扫描。因此在当前活动页销毁的时候,记得添加标识位,且销毁蓝牙连接。
还有需要注意的是扫描会消耗更多电量,可以根据需要适当调整扫码周期
。