You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio基础蓝牙示例崩溃问题求助

Android蓝牙配对设备列表崩溃问题排查与修复

核心崩溃原因

代码崩溃在val pairedDevices = bluetoothAdapter!!.bondedDevices这行,本质是Android 12(API 31)及以上版本的蓝牙危险权限未做动态申请。虽然你在Manifest里声明了BLUETOOTH_CONNECT和BLUETOOTH_SCAN,但这两个权限属于危险权限,必须在运行时向用户申请授权,仅静态声明不会生效,直接调用蓝牙API会触发权限异常导致崩溃。

另外代码还有两个次要问题:

  1. 未调用setContentView()加载布局,ListView根本不会被初始化
  2. 重复获取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 17:34:50