Android蓝牙设备列表异常:已配对设备显示正常,未配对设备不显示
解决未配对蓝牙设备无法加载的问题
老哥,我看了你的代码,已配对设备能正常显示,但未配对设备扫不出来,主要是两个常见问题卡壳了:权限不足和扫描时机不对,我给你一步步捋清楚怎么改:
1. 补充必要的蓝牙扫描权限
从Android 6.0(API 23)开始,蓝牙扫描需要位置相关权限;Android 12(API 31)及以上还新增了专门的蓝牙扫描权限,你得先在AndroidManifest.xml里声明静态权限:
<!-- 基础蓝牙操作权限 --> <uses-permission android:name="android.permission.BLUETOOTH" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" /> <!-- Android 6.0+ 蓝牙扫描必备的位置权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <!-- Android 12+ 专属蓝牙扫描权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- 可选:如果需要让当前设备被其他蓝牙设备发现 --> <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
因为位置权限属于危险权限,必须动态申请,在你的BluetoothListActivity里添加权限检查和申请的方法:
private static final int REQUEST_PERMISSIONS = 1; // 检查是否拥有所需权限 private boolean checkPermissions() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12+ 需同时检查蓝牙扫描和位置权限 return ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED && ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } else { // 低版本仅需检查位置权限 return ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED; } } // 请求权限 private void requestPermissions() { List<String> permissionsNeeded = new ArrayList<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_SCAN) != PackageManager.PERMISSION_GRANTED) { permissionsNeeded.add(Manifest.permission.BLUETOOTH_SCAN); } } if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { permissionsNeeded.add(Manifest.permission.ACCESS_FINE_LOCATION); } if (!permissionsNeeded.isEmpty()) { ActivityCompat.requestPermissions(this, permissionsNeeded.toArray(new String[0]), REQUEST_PERMISSIONS); } }
2. 调整扫描时机,确保蓝牙开启后再启动扫描
你当前代码在onCreate里直接启动扫描,但如果蓝牙是通过ACTION_REQUEST_ENABLE刚开启的,这时候onCreate里的bluetoothAdapter.isEnabled()是false,扫描根本没执行。得在蓝牙启用成功后、权限申请通过后,再启动扫描:
修改onCreate方法,调整初始化逻辑顺序:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth_list); if(bluetoothAdapter == null){ Toast.makeText(this, "Bluetooth not supported.", Toast.LENGTH_SHORT).show(); finish(); return; } // 先初始化适配器和列表控件 pairedDevicesArrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1); newDevicesArrayAdapter=new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1); pairedDevicesList = findViewById(R.id.pairedDevicesListView); newDevicesList = findViewById(R.id.newDevicesListView); pairedDevicesList.setAdapter(pairedDevicesArrayAdapter); newDevicesList.setAdapter(newDevicesArrayAdapter); // 注册广播接收器 IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); this.registerReceiver(broadcastReceiver, filter); filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED); this.registerReceiver(broadcastReceiver,filter); // 加载已配对设备 Set<BluetoothDevice> pairedDevices = bluetoothAdapter.getBondedDevices(); if(pairedDevices.size() > 0 ){ for(BluetoothDevice device : pairedDevices){ pairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress()); } }else{ pairedDevicesArrayAdapter.add("No device found"); } // 先检查权限,再处理蓝牙启用和扫描 if (checkPermissions()) { handleBluetoothAndScan(); } else { requestPermissions(); } }
新增两个辅助方法处理蓝牙状态和扫描:
// 处理蓝牙状态,决定是否启动扫描 private void handleBluetoothAndScan() { if (!bluetoothAdapter.isEnabled()) { Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(i, ENABLE_REQUEST); } else { startBluetoothDiscovery(); } } // 启动蓝牙扫描(先清空旧列表避免重复数据) private void startBluetoothDiscovery() { if (bluetoothAdapter.isDiscovering()) { bluetoothAdapter.cancelDiscovery(); } newDevicesArrayAdapter.clear(); bluetoothAdapter.startDiscovery(); }
最后修改权限申请回调和蓝牙启用回调:
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if(requestCode == ENABLE_REQUEST){ if(resultCode == RESULT_OK){ // 蓝牙启用成功,立即启动扫描 startBluetoothDiscovery(); } else { Toast.makeText(this, "You need to enable the bluetooth.", Toast.LENGTH_SHORT).show(); finish(); } } } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_PERMISSIONS) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted) { handleBluetoothAndScan(); } else { Toast.makeText(this, "Permissions are required to scan Bluetooth devices.", Toast.LENGTH_SHORT).show(); finish(); } } }
3. 额外优化:避免空指针异常
有些蓝牙设备没有名称,直接调用device.getName()会导致空指针,在广播接收器里加个判断:
private final BroadcastReceiver broadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); if (device != null && device.getBondState() != BluetoothDevice.BOND_BONDED) { String deviceName = device.getName(); String deviceAddress = device.getAddress(); // 设备名称为空时,仅显示地址 String displayText = deviceName != null ? deviceName + "\n" + deviceAddress : deviceAddress; newDevicesArrayAdapter.add(displayText); } }else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){ if (newDevicesArrayAdapter.getCount() == 0) { newDevicesArrayAdapter.add("No device found"); } } } };
这样修改后,应该就能正常扫描并显示未配对的蓝牙设备了。
内容的提问来源于stack exchange,提问作者JayJona
相关产品推荐
相关产品推荐

