Bluetooth.ACTION_FOUND异常:扫描设备过多且设备名称为空
蓝牙扫描异常:重复设备与名称为null的解决方案
问题根源分析
- 重复注册广播接收器:每次点击按钮都会调用
registerReceiver,导致多个接收器实例同时监听BluetoothDevice.ACTION_FOUND,同一设备被多次触发接收,表现为扫描出大量重复设备。 - 权限与设备名称限制:Android 12+中获取蓝牙设备名称必须持有
BLUETOOTH_CONNECT权限,部分设备不会主动广播名称,首次扫描时无法直接获取。 - 扫描生命周期未管理:未在扫描结束后注销接收器,也未处理重复扫描场景,导致资源泄漏和重复接收。
具体修复方案
1. 避免重复注册广播接收器
将广播接收器注册移至onCreate,确保仅注册一次;在onDestroy中注销接收器,防止内存泄漏,同时点击按钮时先停止之前的扫描再启动新扫描。
修改后MainActivity代码:
class MainActivity : AppCompatActivity() { private var bluetoothAdapter: BluetoothAdapter? = null private lateinit var receiver: MyBroadcast override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) receiver = MyBroadcast() val bluetoothManager: BluetoothManager = getSystemService(BluetoothManager::class.java) bluetoothAdapter = bluetoothManager.adapter // 仅注册一次广播接收器 IntentFilter(BluetoothDevice.ACTION_FOUND).also { registerReceiver(receiver, it) } // 权限请求 if (ActivityCompat.checkSelfPermission( this, Manifest.permission.BLUETOOTH_CONNECT ) != PackageManager.PERMISSION_GRANTED ) { ActivityCompat.requestPermissions( this, arrayOf( Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.ACCESS_FINE_LOCATION ), 1 ) } val button = findViewById<Button>(R.id.button_b) button.setOnClickListener { Log.i("TAG", "clicked") // 停止之前的扫描,避免重复 bluetoothAdapter?.cancelDiscovery() bluetoothAdapter?.startDiscovery() } } override fun onDestroy() { super.onDestroy() // 注销接收器 unregisterReceiver(receiver) // 停止扫描 bluetoothAdapter?.cancelDiscovery() } }
2. 处理设备名称为null与重复设备
用集合存储已发现设备的MAC地址实现去重,对名称为空的设备显示MAC地址作为标识,同时确保权限充足。
修改后广播接收器代码:
class MyBroadcast : BroadcastReceiver() { private val discoveredDevices = mutableSetOf<String>() override fun onReceive(context: Context?, intent: Intent?) { when (intent?.action) { BluetoothDevice.ACTION_FOUND -> { val device: BluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE)!! // 去重处理 if (!discoveredDevices.contains(device.address)) { discoveredDevices.add(device.address) val deviceName = device.name ?: "未知设备(${device.address})" Log.i("here", "设备名称: $deviceName, MAC地址: ${device.address}") } } } } }
3. 优化权限配置(AndroidManifest.xml)
针对Android版本适配权限,减少不必要的权限申请:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools"> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- Android 11及以下需要定位权限扫描蓝牙 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <uses-feature android:name="android.hardware.bluetooth" android:required="true" /> <uses-feature android:name="android.hardware.bluetooth_le" android:required="false" /> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/Theme.Broadcast" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
额外注意事项
- 蓝牙扫描耗电较高,建议扫描一段时间后主动调用
cancelDiscovery()停止。 - 若扫描BLE设备,建议使用
BluetoothLeScanner替代startDiscovery(),后者主要针对经典蓝牙。 - 部分设备未广播名称时,可尝试主动连接获取名称(需
BLUETOOTH_CONNECT权限)。
内容的提问来源于stack exchange,提问作者jane
相关产品推荐
相关产品推荐

