调用notifyDataSetChanged()时RecyclerView崩溃问题排查
问题分析与解决方案
崩溃原因1:空指针异常(最直接触发崩溃的原因)
在广播接收器中,你直接获取BluetoothDevice对象但未做非空判断:
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); final String deviceName = device.getName();
如果intent中没有BluetoothDevice.EXTRA_DEVICE数据,device会返回null,直接调用device.getName()会抛出NullPointerException,导致应用崩溃。
崩溃原因2:权限判断逻辑完全颠倒
在getPairedDevices()方法中,权限判断条件写反:
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { // 获取配对设备的逻辑 } else { return new String[0]; }
这段代码的逻辑是无BLUETOOTH_CONNECT权限时才去获取配对设备,这会直接触发SecurityException——因为获取绑定设备必须持有该权限。
崩溃原因3:缺少Android 12+蓝牙权限
Android 12(API 31)及以上版本,蓝牙扫描需要BLUETOOTH_SCAN权限,蓝牙连接需要BLUETOOTH_CONNECT权限,你的代码仅申请了位置权限,未添加这些必要权限,会引发权限异常。
崩溃原因4:扫描启动时机错误
在onCreate()的else分支中,你申请权限后立刻调用bluetoothAdapter.startDiscovery(),此时用户尚未完成授权,扫描会直接失败,后续可能引发逻辑异常。
修复方案
1. 修复广播接收器空指针问题
在使用BluetoothDevice前先做非空判断,同时避免重复添加设备:
private final BroadcastReceiver receiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { Log.d("Broadcast", "Broadcast called"); String action = intent.getAction(); if (BluetoothDevice.ACTION_FOUND.equals(action)) { BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 先判断device非空 if (device == null) { return; } final String deviceName = device.getName(); runOnUiThread(new Runnable() { @Override public void run() { if (deviceName != null && !availableDevices.contains(deviceName)) { availableDevices.add(deviceName); adapter2.notifyDataSetChanged(); } } }); } } };
2. 修正配对设备获取的权限逻辑
将权限判断改为有权限时才获取配对设备:
private String[] getPairedDevices() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) == PackageManager.PERMISSION_GRANTED) { Set<BluetoothDevice> bt = bluetoothAdapter.getBondedDevices(); String[] pairedDevices = new String[bt.size()]; int i = 0; for(BluetoothDevice d : bt){ pairedDevices[i] = d.getName(); i++; } return pairedDevices; } else { return new String[0]; } }
3. 添加Android 12+蓝牙权限
在AndroidManifest.xml中补充权限:
<!-- Android 12+ 蓝牙权限 --> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" /> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <!-- 旧版本扫描所需位置权限 --> <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" /> <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" android:maxSdkVersion="30" />
4. 修复扫描启动时机,添加权限回调
重写onRequestPermissionsResult方法,在用户授权后再启动扫描:
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); if (requestCode == REQUEST_BLUETOOTH_PERMISSION) { boolean allGranted = true; for (int result : grantResults) { if (result != PackageManager.PERMISSION_GRANTED) { allGranted = false; break; } } if (allGranted && bluetoothAdapter.isEnabled()) { bluetoothAdapter.startDiscovery(); Toast.makeText(this, "Discovering", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "需要权限才能扫描蓝牙设备", Toast.LENGTH_SHORT).show(); } } }
同时修改onCreate()的else分支,移除提前启动扫描的代码:
else { requestPermissions(new String[]{ Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.BLUETOOTH_SCAN, Manifest.permission.BLUETOOTH_CONNECT }, REQUEST_BLUETOOTH_PERMISSION); }
内容的提问来源于stack exchange,提问作者Shady Abdulmunim
相关产品推荐
相关产品推荐

