API 31环境下使用ActivityResultLauncher实现蓝牙启用时应用崩溃且权限对话框无法弹出的问题求助
看起来你遇到的崩溃大概率是因为ActivityResultLauncher的注册时机不对,或者缺少必要的蓝牙权限导致的。让我一步步帮你解决这个问题:
1. 崩溃的核心原因:registerForActivityResult注册时机错误
registerForActivityResult必须在Activity的onCreate生命周期之前完成注册(比如作为类的成员变量初始化,或者在onCreate方法内部的早期执行)。如果在点击事件、onStart等后续方法中注册,就会抛出IllegalStateException,导致应用崩溃。
看你的代码,如果你是在onCreate内部才注册startForResult,那没问题,但如果是在其他地方(比如检查蓝牙状态的代码块里)注册,那肯定会崩。
2. 必须先申请对应蓝牙权限
不同Android版本对蓝牙操作的权限要求不一样,没有权限的话,不仅可能崩溃,还可能导致权限对话框不显示:
- Android 12+(API 31):需要
BLUETOOTH_CONNECT权限 - Android 10-11(API 29-30):需要
ACCESS_FINE_LOCATION权限(因为扫描蓝牙需要位置权限) - Android 9及以下:需要
BLUETOOTH和BLUETOOTH_ADMIN权限
先把这些权限添加到你的AndroidManifest.xml中:
<!-- 基础蓝牙功能声明 --> <uses-feature android:name="android.hardware.bluetooth" android:required="true" /> <!-- Android 12+ 权限 --> <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" /> <uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation" /> <!-- Android 10-11 权限 --> <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" android:maxSdkVersion="30" /> <!-- Android 9及以下权限 --> <uses-permission android:name="android.permission.BLUETOOTH" android:maxSdkVersion="28" /> <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" android:maxSdkVersion="28" />
3. 完整的修复代码示例
我把你的代码重新整理,确保权限申请和蓝牙开启逻辑正确:
public class MainActivity extends AppCompatActivity { // 提前注册蓝牙开启的Launcher(作为成员变量,确保在onCreate前初始化) private ActivityResultLauncher<Intent> enableBtLauncher; // 权限申请的Launcher private ActivityResultLauncher<String[]> permissionLauncher; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 初始化蓝牙开启的回调 enableBtLauncher = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == RESULT_OK) { // 蓝牙成功开启,这里可以连接你的LED灯带了 Toast.makeText(this, "蓝牙已开启,准备连接设备", Toast.LENGTH_SHORT).show(); } else { // 用户拒绝开启蓝牙 Toast.makeText(this, "你拒绝了开启蓝牙,无法控制灯带", Toast.LENGTH_SHORT).show(); } } ); // 初始化权限申请的回调 permissionLauncher = registerForActivityResult( new ActivityResultContracts.RequestMultiplePermissions(), permissions -> { boolean allPermissionsGranted = true; for (boolean isGranted : permissions.values()) { allPermissionsGranted &= isGranted; } if (allPermissionsGranted) { // 权限都拿到了,检查并开启蓝牙 checkAndEnableBluetooth(); } else { Toast.makeText(this, "需要蓝牙权限才能控制灯带", Toast.LENGTH_SHORT).show(); } } ); // 先申请权限,再处理蓝牙逻辑 requestNecessaryPermissions(); } private void requestNecessaryPermissions() { List<String> requiredPermissions = new ArrayList<>(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { // Android 12+ 检查BLUETOOTH_CONNECT权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_CONNECT) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(Manifest.permission.BLUETOOTH_CONNECT); } } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { // Android 10-11 检查位置权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(Manifest.permission.ACCESS_FINE_LOCATION); } } else { // Android 9及以下 检查蓝牙基础权限 if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(Manifest.permission.BLUETOOTH); } if (ContextCompat.checkSelfPermission(this, Manifest.permission.BLUETOOTH_ADMIN) != PackageManager.PERMISSION_GRANTED) { requiredPermissions.add(Manifest.permission.BLUETOOTH_ADMIN); } } if (!requiredPermissions.isEmpty()) { permissionLauncher.launch(requiredPermissions.toArray(new String[0])); } else { // 权限已经有了,直接检查蓝牙 checkAndEnableBluetooth(); } } private void checkAndEnableBluetooth() { BluetoothManager bluetoothManager = getSystemService(BluetoothManager.class); BluetoothAdapter bluetoothAdapter = bluetoothManager.getAdapter(); if (bluetoothAdapter == null) { Toast.makeText(this, "你的设备不支持蓝牙,无法控制灯带", Toast.LENGTH_SHORT).show(); return; } if (!bluetoothAdapter.isEnabled()) { // 启动蓝牙开启对话框 Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); enableBtLauncher.launch(enableBtIntent); } else { Toast.makeText(this, "蓝牙已经开启,开始连接灯带吧", Toast.LENGTH_SHORT).show(); } } }
关键注意事项
- 确保
registerForActivityResult是在Activity的onCreate方法中或者作为成员变量注册,绝对不能在点击事件等动态逻辑中注册,这是导致崩溃的最常见原因。 - 先申请权限再开启蓝牙,否则系统可能会阻止你的请求,甚至崩溃。
- 因为你只需要控制自己的LED灯带,所以不需要处理旧API的兼容问题,上面的代码已经覆盖了现代Android版本的需求。
内容的提问来源于stack exchange,提问作者Schurkee
相关产品推荐
相关产品推荐

