AndroidBLE開發(fā)的各種坑

這段時間在做低功耗藍(lán)牙(BLE)應(yīng)用的開發(fā)(并不涉及藍(lán)牙協(xié)議棧)??傮w感覺 Android BLE 還是不太穩(wěn)定,開發(fā)起來也是各種痛苦。這里記錄一些雜項和開發(fā)中遇到的問題及其解決方法,避免大家踩坑。本文說的問題有些沒有得到官方文檔的驗證,不過也有一些論壇帖子的支持,也可以算是有一定根據(jù)。

讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:申請域名、虛擬空間、營銷軟件、網(wǎng)站建設(shè)、西鄉(xiāng)網(wǎng)站維護(hù)、網(wǎng)站推廣。

  1. Android 從 4.3(API Level 18) 開始支持低功耗藍(lán)牙,但是只支持作為中心設(shè)備(Central)模式,這就意味著 Android 設(shè)備只能主動掃描和鏈接其他外圍設(shè)備(Peripheral)。從 Android 5.0(API Level 21) 開始兩種模式都支持。BLE 官方文檔在 這里。

  2. 在 BluetoothAdapter.startLeScan() 的時候,在 BluetoothAdapter.LeScanCallback.onLeScan() 中不能做太多事情,特別是周圍的BLE設(shè)備多的時候,非常容易導(dǎo)致出現(xiàn)如下錯誤:

E/GKILINUX(17741): ##### ERROR : GKIexception: GKIexception(): Task State Table E/GKILINUX(17741): ##### 
E/GKILINUX(17741): ##### ERROR : GKIexception: TASK ID [0] task name [BTU] state [1] 
E/GKILINUX(17741): ##### 
E/GKI
LINUX(17741): ##### ERROR : GKIexception: TASK ID [1] task name [BTIF] state [1] 
E/GKI
LINUX(17741): ##### 
E/GKILINUX(17741): ##### ERROR : GKIexception: TASK ID [2] task name [A2DP-MEDIA] state [1] 
E/GKILINUX(17741): ##### 
E/GKI
LINUX(17741): ##### ERROR : GKIexception: GKIexception 65524 getbuf: out of buffers##### 
E/GKILINUX(17741): ##### ERROR : GKIexception: 
E/GKI_LINUX(17741): **********************

開發(fā)建議:在 onLeScan() 回調(diào)中只做盡量少的工作,可以把掃描到的設(shè)備,扔到另外一個線程中去處理,讓 onLeScan() 盡快返回


3、在使用 BluetoothDevice.connectGatt() 或者 BluetoothGatt.connect() 等建立 BluetoothGatt 連接的時候,在任何時刻都只能最多一個設(shè)備在嘗試建立連接。如果同時對多個藍(lán)牙設(shè)備發(fā)起建立 Gatt 連接請求。如果前面的設(shè)備連接失敗了,后面的設(shè)備請求會被永遠(yuǎn)阻塞住,不會有任何連接回調(diào)。

開發(fā)建議:如果要對多個設(shè)備發(fā)起連接請求,最好是有一個同一個的設(shè)備連接管理,把發(fā)起連接請求序列化起來。前一個設(shè)備請求建立連接,后面請求在隊列中等待。如果連接成功了,就處理下一個連接請求。如果連接失敗了(例如出錯,或者連接超時失?。?,就馬上調(diào)用 BluetoothGatt.disconnect() 來釋放建立連接請求,然后處理下一個設(shè)備連接請求。

4、對 BluetoothGatt 操作 (read/write)Characteristic()(read/write)Descriptor() 和 readRemoteRssi() 都是異步操作。需要特別注意的是,同時只能有一個操作(有些貼這說只能同時有一個 writeCharacteristic(),這個我并沒有嚴(yán)格驗證),也就是等上一個操作回調(diào)(例如 onCharacteristicWrite())以后,再進(jìn)行下一個操作。

開發(fā)建議:把這寫操作都封裝成同步操作,一個操作回調(diào)之前,阻塞主其他調(diào)用。


5、BLE 設(shè)備的建立和斷開連接的操作,例如 BluetoothDevice.connectGatt(),BluetoothGatt.connect()BluetoothGatt.disconnect()BluetoothGatt.discoverServices()等操作最好都放在主線程中,否則你會遇到很多意想不到的麻煩。

開發(fā)建議:對 BluetoothGatt 的連接和斷開請求,都通過發(fā)送消息到 Android 的主線程中,讓主線程來執(zhí)行具體的操作。例如創(chuàng)建一個 new Handler(context.getMainLooper());,把消息發(fā)送到這個 Handler 中

6、如果你在開發(fā) BLE 應(yīng)用的時候,有時候會發(fā)現(xiàn)系統(tǒng)的功耗明顯增加了,查看電量使用情況,藍(lán)牙功耗占比非常高,好像低功耗是徒有虛名。使用 adb bugreport 獲取的了系統(tǒng)信息,分析發(fā)現(xiàn)一個名叫 BluetoothRemoteDevices的 WakeLock 鎖持有時間非常長,導(dǎo)致系統(tǒng)進(jìn)入不了休眠。分析源代碼發(fā)現(xiàn),在連接 BLE 設(shè)備的過程中,系統(tǒng)會持有 (Aquire)這個 WakeLock,直到連接上或者主動斷開連接(調(diào)用 disconnect())才會釋放。如果BLE設(shè)備不在范圍內(nèi),這個超時時間大約為30s,而這時你可能又要嘗試重新連接,這個 WakeLock 有被重新持有,這樣系統(tǒng)就永遠(yuǎn)不能休眠了。

開發(fā)建議:對BLE設(shè)備連接,連接過程要盡量短,如果連接不上,不要盲目進(jìn)行重連,否這你的電池會很快被消耗掉。這個情況,實(shí)際上對傳統(tǒng)藍(lán)牙設(shè)備連接也是一樣。

7、Android 作為中心設(shè)備,最多只能同時連接 6 個 BLE 外圍設(shè)備(可能不同的設(shè)備這個數(shù)字不一樣),超過 6 個,就會連接不上了?,F(xiàn)在 BLE 設(shè)備越來越多,其實(shí)并不夠用,所以在開發(fā)的過程中,需要特別的謹(jǐn)慎使用。

開發(fā)建議:按照需要連接設(shè)備,如果設(shè)備使用完了,應(yīng)該馬上釋放連接(調(diào)用BluetoothGatt.close()),騰出系統(tǒng)資源給其他可能的設(shè)備連接。

8、發(fā)起藍(lán)牙Gatt連接 BluetoothDevice.connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback),這里有一個參數(shù)autoConnect,如果為 true 的話,系統(tǒng)就會發(fā)起一個后臺連接,等到系統(tǒng)發(fā)現(xiàn)了一個設(shè)備,就會自動連上,通常這個過程是非常慢的。為 false 的話,就會直接連接,通常會比較快。同樣,BluetoothGatt.connect()只能發(fā)起一個后臺連接,不是直接連接。所以這個地方需要小心。

public boolean connect() {
    try {
        mService.clientConnect(mClientIf, mDevice.getAddress(),
                               false, mTransport); // autoConnect is inverse of "isDirect"
        return true;
    } catch (RemoteException e) {
        Log.e(TAG,"",e);
        return false;
    }
}

開發(fā)建議:如果你需要快速連接(通常情況下我們都希望這樣),在 connectGatt()的時候,傳入 autoConnect=false 的參數(shù)。如果需要調(diào)用 BluetoothGatt.connect() 連接,可一通過反射的方式,強(qiáng)制 mService.clientConnect() 發(fā)起直接連接,也就是傳入?yún)?shù) isDirect=true。

當(dāng)前標(biāo)題:AndroidBLE開發(fā)的各種坑
分享地址:http://muchs.cn/article42/iehsec.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制網(wǎng)站、靜態(tài)網(wǎng)站電子商務(wù)、微信公眾號建站公司、網(wǎng)站收錄

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

搜索引擎優(yōu)化