Android Studio基础蓝牙示例崩溃问题求助
Android蓝牙配对设备列表崩溃问题排查与修复
核心崩溃原因
代码崩溃在val pairedDevices = bluetoothAdapter!!.bondedDevices这行,本质是Android 12(API 31)及以上版本的蓝牙危险权限未做动态申请。虽然你在Manifest里声明了BLUETOOTH_CONNECT和BLUETOOTH_SCAN,但这两个权限属于危险权限,必须在运行时向用户申请授权,仅静态声明不会生效,直接调用蓝牙API会触发权限异常导致崩溃。
另外代码还有两个次要问题:
- 未调用
setContentView()加载布局,ListView根本不会被初始化 - 重复获取
BluetoothAdapter,存在冗余代码
分步修复方案
1. 实现动态权限申请逻辑
在访问蓝牙设备前,必须先检查并申请权限:
import android.Manifest import android.app.Activity import android.bluetooth.BluetoothAdapter import android.bluetooth.BluetoothManager import android.content.pm.PackageManager import android.os.Build import android.os.Bundle import android.widget.ArrayAdapter import android.widget.ListView import android.widget.Toast import androidx.core.app.ActivityCompat import androidx.core.content.ContextCompat class MainActivity : Activity() { private val REQUEST_BLUETOOTH_PERMISSIONS = 1001 private val bluetoothPermissions: Array<String> get() = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { arrayOf( Manifest.permission.BLUETOOTH_CONNECT, Manifest.permission.BLUETOOTH_SCAN ) } else { arrayOf( Manifest.permission.BLUETOOTH, Manifest.permission.BLUETOOTH_ADMIN ) } override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // 必须先加载布局 // 优先检查权限 if (hasAllPermissions()) { initBluetoothDeviceList() } else { requestPermissions() } } // 检查所有必要权限是否已授予 private fun hasAllPermissions(): Boolean { return bluetoothPermissions.all { ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED } } // 向用户申请权限 private fun requestPermissions() { ActivityCompat.requestPermissions( this, bluetoothPermissions, REQUEST_BLUETOOTH_PERMISSIONS ) } // 处理权限申请结果 override fun onRequestPermissionsResult( requestCode: Int, permissions: Array<out String>, grantResults: IntArray ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) if (requestCode == REQUEST_BLUETOOTH_PERMISSIONS) { if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) { initBluetoothDeviceList() } else { Toast.makeText(this, "拒绝蓝牙权限将无法获取设备列表", Toast.LENGTH_SHORT).show() } } }
2. 修复蓝牙设备列表加载逻辑
将蓝牙相关操作封装到initBluetoothDeviceList()方法中,确保仅在权限授予后执行:
@SuppressLint("MissingPermission") private fun initBluetoothDeviceList() { val bluetoothManager = getSystemService(BluetoothManager::class.java) val bluetoothAdapter = bluetoothManager.adapter bluetoothAdapter?.let { adapter -> if (adapter.isEnabled) { Toast.makeText(this, "蓝牙已开启", Toast.LENGTH_LONG).show() // 获取已配对设备 val pairedDevices = adapter.bondedDevices val deviceNames = pairedDevices.map { it.name ?: "未知设备" }.toMutableList() // 绑定ListView到布局(确保你的activity_main.xml中有id为list_view的ListView) val listView = findViewById<ListView>(R.id.list_view) val listAdapter = ArrayAdapter(this, android.R.layout.simple_list_item_1, deviceNames) listView.adapter = listAdapter } else { Toast.makeText(this, "蓝牙已关闭", Toast.LENGTH_LONG).show() } } ?: run { Toast.makeText(this, "当前设备不支持蓝牙", Toast.LENGTH_LONG).show() } } }
3. 优化Manifest权限声明
对于API31+,可以给BLUETOOTH_SCAN添加neverForLocation标记,避免不必要的位置权限请求(仅适用于获取配对设备的场景):
<uses-permission android:name="android.permission.BLUETOOTH_SCAN" android:usesPermissionFlags="neverForLocation"/>
关键注意事项
- 不要随意使用
@SuppressLint("MissingPermission"),仅在确认权限已授予的代码块中添加,避免掩盖权限问题 - 确保你的布局文件
activity_main.xml中存在ListView组件,且id为list_view - 如果后续需要扫描未配对设备,API29及以下版本还需要申请位置权限,当前需求仅需获取配对设备,无需额外处理
内容的提问来源于stack exchange,提问作者John B Gilbert
相关产品推荐
相关产品推荐

