
    
    
    前言
   
随着BLE蓝牙技术的发展,利用蓝牙进行数据信息交互变得越来越常见。但是Android的蓝牙扫描默认只是一次性的短时间扫描。为了实现持续扫描的效果,我们需要自定义扫描逻辑。
蓝牙是一种让设备在短距离内进行无线通信的技术。在Android系统上,我们可以通过蓝牙API以编程方式扫描附近的蓝牙设备。
默认情况下,蓝牙扫描只会执行一次并返回发现的设备列表。但是,我们通常需要持续一段时间扫描蓝牙设备。这样可以检测到初始扫描时可能关闭或不在范围内的设备。

那么我们该如何实现蓝牙持续扫描的方法呢?接下来让我们一起来看看吧!
最近项目开发中,对于蓝牙血糖仪测量模块在实际应用中,需要让蓝牙持续扫描,根据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秒都会执行扫描
    
    。每当退出蓝牙连接界面后,它会一直扫描。因此在当前活动页销毁的时候,记得添加标识位,且销毁蓝牙连接。
   
    还有需要注意的是
    
     扫描会消耗更多电量,可以根据需要适当调整扫码周期
    
    。
   
 
