一、基礎流程
請簡述 Android 藍牙開發的基本流程
1. 權限處理:動態申請藍牙和定位權限(注意Android 12+新權限)
2. 初始化藍牙適配器:通過BluetoothManager獲取BluetoothAdapter
3. 設備發現:- 注冊BroadcastReceiver監聽ACTION_FOUND- 調用startDiscovery()開始搜索- 通過bondedDevices獲取已配對設備
4. 建立連接:- 客戶端:createRfcommSocketToServiceRecord()- 服務端:listenUsingRfcommWithServiceRecord()
5. 數據傳輸:通過BluetoothSocket的InputStream/OutputStream
6. 資源釋放:及時關閉Socket和取消搜索
加分項:
-
提到經典藍牙與BLE的區別(傳輸速率/功耗/使用場景)
-
強調Android 6.0+需要運行時定位權限
二、高頻技術細節
1. 權限適配(重點!)
如何處理不同Android版本的藍牙權限?
最佳回答:
// 代碼示例+解釋
val permissions = mutableListOf<String>().apply {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {add(Manifest.permission.BLUETOOTH_SCAN)add(Manifest.permission.BLUETOOTH_CONNECT)} else {add(Manifest.permission.BLUETOOTH)add(Manifest.permission.BLUETOOTH_ADMIN)}// 設備發現需要定位權限add(Manifest.permission.ACCESS_FINE_LOCATION)
}// 檢查并申請權限
if (permissions.any { checkSelfPermission(it) != PERMISSION_GRANTED }) {requestPermissions(permissions.toTypedArray(), REQUEST_CODE)
}
關鍵點:
-
Android 12(API 31)開始必須使用新權限
-
定位權限在搜索設備時必需
2. 連接失敗排查
藍牙連接失敗可能有哪些原因?
排查清單:
1. 權限未正確申請(尤其Android 12+)
2. 設備未處于可發現模式
3. UUID不匹配(經典藍牙默認用00001101-0000-1000-8000-00805F9B34FB)
4. 未在子線程執行連接操作(主線程會阻塞)
5. 設備距離過遠或已斷開
6. 未調用cancelDiscovery()(正在搜索時無法連接)
三、高階實戰技巧
1. 自動重連機制
如何實現藍牙斷開后自動重連?
解決方案:
// 方案1:定時重試
private fun reconnect(device: BluetoothDevice, retryCount: Int = 3) {var attempts = 0val handler = Handler(Looper.getMainLooper())fun attemptConnect() {if (attempts >= retryCount) returnthread {try {device.createRfcommSocketToServiceRecord(UUID.randomUUID()).use { socket ->socket.connect()// 連接成功...}} catch (e: IOException) {handler.postDelayed({ attemptConnect() }, 5000) // 5秒后重試attempts++}}}attemptConnect()
}// 方案2:監聽連接狀態(廣播接收器)
private val connectionReceiver = object : BroadcastReceiver() {override fun onReceive(context: Context, intent: Intent) {when(intent.action) {BluetoothAdapter.ACTION_STATE_CHANGED -> {val state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1)if (state == BluetoothAdapter.STATE_OFF) {// 觸發重連邏輯}}}}
}
2. 數據傳輸優化
如何保證藍牙數據傳輸的可靠性?
優化策略:
1. 數據分包:大數據拆分為≤512字節的包
2. 校驗機制:添加CRC校驗或使用協議頭尾標記
3. 確認應答:接收方回復ACK確認
4. 超時重傳:設置500ms超時未收到ACK則重發
5. 隊列管理:使用LinkedBlockingQueue控制發送速率
四、BLE藍牙補充
說說BLE和經典藍牙的區別?
對比表(速記關鍵點):
維度 | 經典藍牙 | BLE |
---|---|---|
功耗 | 高(~1mA) | 極低(~0.01mA) |
延遲 | 高(~100ms) | 低(~6ms) |
傳輸速率 | 2.1 Mbps | 0.27 Mbps |
有效距離 | 10米 | 30米 |
典型場景 | 音頻傳輸、文件共享 | 傳感器數據、IoT設備 |
BLE核心操作:
// 掃描BLE設備
val scanner = bluetoothAdapter.bluetoothLeScanner
scanner.startScan(scanCallback) // 需實現ScanCallback// 連接GATT
device.connectGatt(context, false, gattCallback)
五、避坑指南
終極話術模板
請描述一個你實現的藍牙功能模塊
在智能硬件項目中,我負責開發了Android端藍牙通信模塊:
1. 架構設計:- 采用MVP分層,藍牙服務獨立為Singleton- 使用RxJava封裝異步操作
2. 關鍵實現:- 實現自動重連機制(指數退避算法)- 設計二進制協議保證數據傳輸可靠性- 添加心跳包檢測連接狀態
3. 難點解決:- 解決Android 12權限適配問題- 優化多設備連接時的資源競爭
4. 性能指標:- 傳輸成功率從85%提升至99.6%- 平均連接時間縮短至1.2秒
-
必問問題:
-
"藍牙連接為什么要在子線程執行?"
→ 主線程阻塞會導致ANR,連接操作可能耗時較長
-
-
致命錯誤:
-
忘記調用
cancelDiscovery()
(正在搜索時無法建立連接) -
未處理Android 12+的
BLUETOOTH_CONNECT
權限
-
-
加分回答:
-
提到藍牙廣播的
IntentFilter
需要動態注冊 -
強調
BluetoothSocket
需要try-with-resources或手動close
-