You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android配置变更后BLE扫描无法停止的问题排查与解决

Android BLE扫描在屏幕旋转后无法停止的问题解决

我开发了一款简单的Android应用,用来扫描BLE(Bluetooth Low Energy)广播包并在屏幕上显示内容。界面有一个按钮用于切换扫描状态:未扫描时点击开始扫描,扫描中时点击停止扫描。无配置变更时功能正常,但启动扫描后旋转设备,再尝试停止扫描毫无反应——扫描会持续进行,仍能收到ScanCallback回调,后续再次点击按钮或旋转回原方向也无法停止扫描。

初始核心代码

class MainActivity : ComponentActivity() {
  private val mainViewModel: MainViewModel by viewModels()

  private val bluetoothAdapter: BluetoothAdapter? by lazy {
    val bluetoothManager: BluetoothManager =
      getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
    bluetoothManager.adapter
  }
  
  private val bleScanner: BluetoothLeScanner? by lazy {
    bluetoothAdapter?.bluetoothLeScanner
  }

  private val scanCallback = object : ScanCallback() {
    override fun onScanResult(callbackType: Int, result: ScanResult?) {
      super.onScanResult(callbackType, result)
      
      Log.d("ScanCallBack", "${result}")
    }
  }

  @SuppressLint("MissingPermission")
  private fun toggleScan() {
    if (bleScanner == null) {
      return
    }
    
    if (mainViewModel.scanActive) {
      bleScanner?.stopScan(scanCallback)
    } else {
      bleScanner?.startScan(buildScanFilters(), buildScanSettings(), scanCallback)
    }
    
    mainViewModel.scanActive = !mainViewModel.scanActive
    mainViewModel.updateScanActive(mainViewModel.scanActive)
  }

}

注:蓝牙启用及运行时权限相关代码未展示

排查过程

  • 已知停止BLE扫描必须传入和启动时完全相同的ScanCallback实例,但屏幕旋转会重建Activity,导致配置变更后停止扫描使用的是新的ScanCallback实例,这一点已通过Log.d()验证。
  • 尝试将ScanCallback移入ViewModel中,确保配置变更后实例引用一致,修改后的核心逻辑代码如下:
if (mainViewModel.scanActive) {
  bleScanner?.stopScan(mainViewModel.scanCallback)
} else {
  bleScanner?.startScan(buildScanFilters(), buildScanSettings(), mainViewModel.scanCallback)
}
  • 确认ScanCallback引用地址一致后,问题仍未解决。推测BluetoothAdapter和BluetoothLeScanner的引用也需要保持不变,但直接将这两个对象移入ViewModel会因缺少Context报错,且不建议将蓝牙相关对象放入ViewModel。

解决方法

改用Application Context获取BluetoothManager,保证BluetoothAdapter和BluetoothLeScanner的实例在配置变更后不会重建,同时保留ViewModel中的ScanCallback,修改后的代码如下:

private val bluetoothAdapter: BluetoothAdapter? by lazy {
  val bluetoothManager: BluetoothManager =
   applicationContext.getSystemService(Context.BLUETOOTH_SERVICE) as BluetoothManager
  bluetoothManager.adapter
}

此方法有效,旋转设备后可正常停止扫描。

内容的提问来源于stack exchange,提问作者l'hiverviendra

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 15:36:27