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
相关产品推荐
相关产品推荐

