(1)藍牙回調
安卓4.4的藍牙回調是在異步線程中(不在主線程),若要在藍牙回調中執行更新界面的操做,記得切換到主線程去操做html
(2)三星手機兼容性問題connectGatt()
方法在某些三星手機上只能在UI線程調用。android
備註:三星的手機是connet和disconnet還有connectGatt都要在UI線程中操做緩存
(3)Android L 新API
Android L換了一套掃描設備的API:BluetoothLeScanner.startScan(List, ScanSettings, ScanCallback)
異步
(4)Android M新的權限(android 6.0 動態權限)
Android M中必須擁有定位權限才能掃描BLE設備ide
(4)鏈接不斷開的問題
別的BLE程序非法保留鏈接的設備可能會致使鏈接不能斷開oop
(5)異步問題
讀寫Characteristic、Descriptor等幾乎全部BLE操做結果都爲異步返回,若不等待上一次操做結果返回就執行下一次操做,極可能致使操做失敗或者操做無效。onDescriptorWrite()
返回的線程與寫入線程爲同一個線程,別的操做通常在不一樣的線程回調。ui
(6)設備緩存
Android會對鏈接過的BLE設備的Services進行緩存,若設備升級後Services等有改動,則程序會出現通信失敗。此時就得刷新緩存,可是刷新緩存的方法並無開放,這裏只能使用反射來調用BluetoothGatt
類中的refresh()
方法:google
1 try { 2 Method localMethod = mBluetoothGatt.getClass().getMethod("refresh"); 3 if (localMethod != null) { 4 return (Boolean) localMethod.invoke(mBluetoothGatt); 5 } 6 } catch (Exception localException) { 7 Log.e("refreshServices()", "An exception occured while refreshing device"); 8 }
(7)掃描設備startLeScan(UUID[], BluetoothAdapter.LeScanCallback)
spa
在Android4.4及如下手機中彷佛只支持16位的短UUID,不支持128位完整的UUID。線程
(9)任何出錯,超時,用完就立刻調用Gatt.disconnect(), Gatt.close()。
(10)從bindService 到 onServiceConnected 這個回調花費時間較長, onServiceConnected 這個回調極可能在 MainActivity onResume以後才執行, 因此不要期望onResume裏去執行掃描,由於此時serviceConnected 回調都還沒有執行
(11)getBtAdapter().enable()是異步,當即返回,但從 off 到 on 的過程須要一個時間因此只能監聽系統broadcast發出的intent裏的state
(12) 屢次掃描藍牙,在華爲榮耀,魅族M3 NOTE 中有的機型,會發現屢次斷開–掃描–斷開–掃描… 會掃描不到設備,此時須要在斷開鏈接後,不能當即掃描,而是要先中止掃描後,過2秒再掃描才能掃描到設備。
(13)掃描儘可能不要放在主線程進行,能夠放入子線程裏。否則有些機型會出現 do too many work in main thread.
(14)設備的gatt在不用時要及時關閉,系統支持的鏈接句柄數是有限的,當達到上限後沒法再創建新的鏈接了。
(15)當鏈接斷開後要調closeGatt釋放資源,不用調disconnect,也不要下次複用以前的gatt來reconnect,由於有的手機上重連可能會存在問題,好比重連後死活發現不了service。這種狀況下,最好只要斷開鏈接就close gatt,下次鏈接時打開全新的gatt,這樣就能夠發現service了。
(16)BLE的特徵一次讀寫最大長度20字節。
(17)一個主設備(例如Android手機)能夠同時鏈接多個從設備(通常爲6個,例如智能硬件。超過就鏈接不上了),一個從設備只能被一個主設備鏈接,一旦從設備鏈接上主設備,就中止廣播,斷開鏈接則繼續廣播。在任什麼時候刻都只能最多一個設備在嘗試創建鏈接。若是同時對多個藍牙設備發起創建Gatt鏈接請求。若是前面的設備鏈接失敗了,則後面的設備請求會被永遠阻塞住,不會有任何鏈接回調。因此建議:若是要對多個設備發起鏈接請求,最好是一個接一個的順序同步請求管理。
(18)對藍牙設備的操做不能並行,只能串行,即每次都要在收到上一個操做的回調後才能繼續下一個操做。可是斷開鏈接例外,斷開鏈接要立刻closeGatt,不用等任務隊列中的其餘操做了。並且要給全部正在執行或者準備執行的任務都cancel。
(19)有時候藍牙協議棧出現異常可能收不到回調,因此咱們要對每一個操做作超時檢查,不然後面的全部操做都被阻塞了。
(20)對於超時的任務,最好closeGatt,下次從新鏈接的時候重開一個gatt。
(21)藍牙鏈接可能不穩定,最好支持失敗自動重試機制,尤爲是鏈接和發現服務,由於80%的問題都發生在創建鏈接和發現服務的時候,並且這一塊也是最耗時的。
(22)Android 從 4.3(API Level 18) 開始支持低功耗藍牙,可是隻支持做爲中心設備 (Central) 模式,這就意味着 Android 設備只能主動掃描和連接其餘外圍設備 (Peripheral)。從Android 5.0(API Level 21)開始兩種模式都支持。BLE 官方文檔在 這裏 。
(23)
在 BluetoothAdapter.startLeScan()
的時候,在 BluetoothAdapter.LeScanCallback.onLeScan()
中不能作太多事情,特別是周圍的BLE設備多的時候,很是容易致使出現以下錯誤:
E/GKI LINUX(17741): ##### ERROR : GKI exception: GKI exception(): Task State Table E/GKI LINUX(17741): #####
E/GKI LINUX(17741): ##### ERROR : GKI exception: TASK ID [0] task name [BTU] state [1]
E/GKI
LINUX(17741): #####
LINUX(17741): ##### ERROR : GKIexception: TASK ID [1] task name [BTIF] state [1]
LINUX(17741): #####
E/GKI LINUX(17741): ##### ERROR : GKI exception: TASK ID [2] task name [A2DP-MEDIA] state [1]
E/GKI
LINUX(17741): #####
LINUX(17741): ##### ERROR : GKI exception: GKI exception 65524 getbuf: out of buffers#####
E/GKI LINUX(17741): ##### ERROR : GKI exception:
E/GKI_LINUX(17741): * * * * * * * * * * * * * * * * * * * * * *
開發建議:在 onLeScan()
回調中只作儘可能少的工做,能夠把掃描到的設備,扔到另一個線程中去處理,讓 onLeScan()
儘快返回。 [ 參考帖子 ]
(24)BLE 設備的創建和斷開鏈接的操做,例如 BluetoothDevice.connectGatt()
, BluetoothGatt.connect()
, BluetoothGatt.disconnect()
等操做最好都放在主線程中,不然你會遇到不少意想不到的麻煩。
開發建議:對 BluetoothGatt
的鏈接和斷開請求,都經過發送消息到 Android 的主線程中,讓主線程來執行具體的操做。例如建立一個 new Handler(context.getMainLooper());
,把消息發送到這個 Handler
中。 [ 參考帖子 ]
(25)
若是你在開發 BLE 應用的時候,有時候會發現系統的功耗明顯增長了,查看電量使用狀況,藍牙功耗佔比很是高,好像低功耗是徒有虛名。使用 adb bugreport
獲取的了系統信息,分析發現一個名叫 BluetoothRemoteDevices
的 WakeLock
鎖持有時間很是長,致使系統進入不了休眠。分析源代碼發現,在鏈接 BLE 設備的過程當中,系統會持有 (Aquire) 這個 WakeLock
,直到鏈接上或者主動斷開鏈接(調用 disconnect()
)纔會釋放。若是BLE設備不在範圍內,這個超時時間大約爲30s,而這時你可能又要嘗試從新鏈接,這個 WakeLock
有被從新持有,這樣系統就永遠不能休眠了。
開發建議:對BLE設備鏈接,鏈接過程要儘可能短,若是鏈接不上,不要盲目進行重連,否這你的電池會很快被消耗掉。這個狀況,實際上對傳統藍牙設備鏈接也是同樣。 [ 參考帖子 ]
(26)
Android 做爲中心設備,最多隻能同時鏈接 6 個 BLE 外圍設備(可能不一樣的設備這個數字不同),超過 6 個,就會鏈接不上了。如今 BLE 設備愈來愈多,其實並不夠用,因此在開發的過程當中,須要特別的謹慎使用。
開發建議:按照須要鏈接設備,若是設備使用完了,應該立刻釋放鏈接(調用 BluetoothGatt.close()
),騰出系統資源給其餘可能的設備鏈接。 [ 參考帖子 ]