如何将BroadcastReceiver的蓝牙扫描数据传递到MainActivity等其他类
Android蓝牙扫描逻辑封装及设备数据回传方案
你提到的Observer模式是该场景下非常推荐的最佳实践,除此之外也可以用更轻量的接口回调方案,两种实现方式如下:
方案1:接口回调(轻量无依赖,适合简单项目)
不需要引入额外组件,实现成本最低
步骤1:定义回调接口
interface BluetoothScanCallback { fun onDeviceFound(device: BluetoothDevice) // 可选扩展其他状态回调 fun onScanStarted() = Unit fun onScanFinished() = Unit fun onScanError(errorCode: Int) = Unit }
步骤2:封装独立扫描管理类
将广播注册、扫描启停逻辑全部封装到独立类中,注意使用ApplicationContext避免内存泄漏
class BluetoothScanner(private val context: Context) { private var scanCallback: BluetoothScanCallback? = null private val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == BluetoothDevice.ACTION_FOUND) { val device: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) device?.let { scanCallback?.onDeviceFound(it) } } } } fun setScanCallback(callback: BluetoothScanCallback) { this.scanCallback = callback } fun startScan() { // 此处可自行补充蓝牙权限、蓝牙开关状态检查逻辑 val filter = IntentFilter(BluetoothDevice.ACTION_FOUND) context.registerReceiver(receiver, filter) BluetoothAdapter.getDefaultAdapter()?.startDiscovery() scanCallback?.onScanStarted() } fun stopScan() { runCatching { context.unregisterReceiver(receiver) BluetoothAdapter.getDefaultAdapter()?.cancelDiscovery() scanCallback?.onScanFinished() scanCallback = null // 销毁回调引用避免泄漏 } } }
步骤3:MainActivity中调用
class MainActivity : AppCompatActivity() { private lateinit var bluetoothScanner: BluetoothScanner override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 传入ApplicationContext避免持有Activity引用 bluetoothScanner = BluetoothScanner(applicationContext) bluetoothScanner.setScanCallback(object : BluetoothScanCallback { override fun onDeviceFound(device: BluetoothDevice) { val deviceName = device.name val macAddress = device.address // 扫描结果回调默认在广播线程,更新UI需要切到主线程 runOnUiThread { // 此处执行更新列表等UI操作 } } override fun onScanStarted() { // 展示扫描中状态 } override fun onScanFinished() { // 隐藏扫描中状态 } }) // 示例:点击按钮触发扫描 btnStartScan.setOnClickListener { // 先申请蓝牙相关权限再调用扫描 bluetoothScanner.startScan() } } override fun onDestroy() { super.onDestroy() // 页面销毁时必须停止扫描,避免广播泄漏 bluetoothScanner.stopScan() } }
方案2:Observer模式(基于Jetpack LiveData,适合Jetpack生态项目)
自动感知Activity生命周期,不需要手动注销回调,原生支持UI线程回调,能有效避免内存泄漏
扫描类封装
class BluetoothScanner(private val context: Context) { // 扫描到的设备通过LiveData对外暴露 val foundDeviceLiveData = MutableLiveData<BluetoothDevice>() val scanStateLiveData = MutableLiveData<ScanState>() // 扫描状态密封类 sealed class ScanState { object Idle : ScanState() object Scanning : ScanState() object Finished : ScanState() data class Error(val code: Int) : ScanState() } private val receiver = object : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { if (intent.action == BluetoothDevice.ACTION_FOUND) { val device: BluetoothDevice? = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE) device?.let { foundDeviceLiveData.postValue(it) } } } } fun startScan() { // 权限、蓝牙状态检查逻辑省略 val filter = IntentFilter(BluetoothDevice.ACTION_FOUND) context.registerReceiver(receiver, filter) BluetoothAdapter.getDefaultAdapter()?.startDiscovery() scanStateLiveData.postValue(ScanState.Scanning) } fun stopScan() { runCatching { context.unregisterReceiver(receiver) BluetoothAdapter.getDefaultAdapter()?.cancelDiscovery() scanStateLiveData.postValue(ScanState.Finished) } } }
MainActivity中观察数据
class MainActivity : AppCompatActivity() { private lateinit var bluetoothScanner: BluetoothScanner override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) bluetoothScanner = BluetoothScanner(applicationContext) // 观察扫描到的设备 bluetoothScanner.foundDeviceLiveData.observe(this) { device -> // LiveData自动在UI线程回调,可直接更新UI val deviceName = device.name val macAddress = device.address // 执行列表更新等操作 } // 观察扫描状态 bluetoothScanner.scanStateLiveData.observe(this) { state -> when(state) { is BluetoothScanner.ScanState.Scanning -> // 展示加载状态 is BluetoothScanner.ScanState.Finished -> // 隐藏加载状态 is BluetoothScanner.ScanState.Error -> // 提示扫描错误 else -> {} } } } override fun onDestroy() { super.onDestroy() bluetoothScanner.stopScan() } }
注意事项
- 不同Android版本蓝牙权限要求不同:Android 12及以上需要申请
BLUETOOTH_SCAN、BLUETOOTH_CONNECT权限,低版本需要申请蓝牙基础权限和定位权限 - 如果需要过滤重复扫描到的设备,可以在扫描类中新增
HashSet<String>存储已扫描到的MAC地址,重复设备不回调即可
内容的提问来源于stack exchange,提问作者chimera
相关产品推荐
相关产品推荐

