天天看點

Android藍牙開發的各種坑

一、對藍牙裝置的操作不能并行,隻能串行,即每次都要在收到上一個操作的回調後才能繼續下一個操作。但是斷開連接配接例外,斷開連接配接要馬上closeGatt,不用等任務隊列中的其他操作了。而且要給所有正在執行或者準備執行的任務都cancel。

二、有時候藍牙協定棧出現異常可能收不到回調,是以我們要對每個操作做逾時檢查,否則後面的所有操作都被阻塞了。

三、對于逾時的任務,最好closeGatt,下次重新連接配接的時候重開一個gatt。

四、藍牙連接配接可能不穩定,最好支援失敗自動重試機制,尤其是連接配接和發現服務,因為80%的問題都發生在建立連接配接和發現服務的時候,而且這一塊也是最耗時的。

五、同一個裝置的所有操作最好都放在同一個線程串行執行,最好不要放在UI線程,雖然這些操作都是異步的,理論上來說不會耗時,但是由于涉及到跨程序,還是有可能出現ANR。另外不建議每個裝置都開一個線程,裝置多了會費記憶體也會降低性能。較好的做法是開一個線程,所有裝置的操作都在該線程中發起,雖然占用同一個線程,但是每個裝置各自維護自己的任務隊列。

六、裝置的gatt在不用時要及時關閉,系統支援的連接配接句柄數是有限的,當達到上限後無法再建立新的連接配接了。

七、當連接配接斷開後要調closeGatt釋放資源,不用調disconnect,也不要下次複用之前的gatt來reconnect,因為有的手機上重連可能會存在問題,比如重連後死活發現不了service。這種情況下,最好隻要斷開連接配接就close gatt,下次連接配接時打開全新的gatt,這樣就可以發現service了。

八、BLE的特征一次讀寫最大長度20位元組。

九. Android手機會對連接配接過的BLE裝置的Services進行緩存,若裝置更新後Services等有改動,則程式會出現通訊失敗。此時就得重新整理緩存,反射調用BluetoothGatt類總的refresh()方法。

十、connectGatt() 在某些三星手機上隻能在UI線程調用。

十一、Android L 新API掃描裝置換為 startScan(List, ScanSettings, ScanCallback)。

十二、 Android M 必須擁有定位權限才能掃描BLE裝置。

十三、一個主裝置(例如Android手機)可以同時連接配接多個從裝置(一般為6個,例如智能硬體。超過就連接配接不上了),一個從裝置隻能被一個主裝置連接配接,一旦從裝置連接配接上主裝置,就停止廣播,斷開連接配接則繼續廣播。在任何時刻都隻能最多一個裝置在嘗試建立連接配接。如果同時對多個藍牙裝置發起建立Gatt連接配接請求。如果前面的裝置連接配接失敗了,則後面的裝置請求會被永遠阻塞住,不會有任何連接配接回調。是以建議:如果要對多個裝置發起連接配接請求,最好是一個接一個的順序同步請求管理。

十四、任何出錯,逾時,用完就馬上調用Gatt.disconnect(), Gatt.close()。

十五、從bindService 到 onServiceConnected 這個回調花費時間較長, onServiceConnected 這個回調很可能在 MainActivity onResume之後才執行, 是以不要指望onResume裡去執行掃描,因為此時serviceConnected 回調都尚未執行

十六、getBtAdapter().enable()是異步,立即傳回,但從 off 到 on 的過程需要一個時間是以隻能監聽系統broadcast發出的intent裡的state

十七、 多次掃描藍牙,在華為榮耀,魅族M3 NOTE 中有的機型,會發現多次斷開–掃描–斷開–掃描… 會掃描不到裝置,此時需要在斷開連接配接後,不能立即掃描,而是要先停止掃描後,過2秒再掃描才能掃描到裝置。

十八、掃描盡量不要放在主線程進行,可以放入子線程裡。不然有些機型會出現 do too many work in main thread.