低功耗蓝牙 (BLE)开发各类坑

这段时间在作低功耗蓝牙 (BLE) 应用的开发(并不涉及蓝牙协议栈)。整体感受 Android BLE 仍是不太稳定,开发起来也是各类痛苦。这里记录一些杂项和开发中遇到的问题及其解决方法,避免你们踩坑。本文说的问题有些没有获得官方文档的验证,不过也有一些论坛帖子的支持,也能够算是有必定根据。html

  1. Android 从 4.3(API Level 18) 开始支持低功耗蓝牙,可是只支持做为中心设备 (Central) 模式,这就意味着 Android 设备只能主动扫描和连接其余外围设备 (Peripheral)。从Android 5.0(API Level 21)开始两种模式都支持。BLE 官方文档在  这里 。 android

  2. 在  BluetoothAdapter.startLeScan() 的时候,在 BluetoothAdapter.LeScanCallback.onLeScan() 中不能作太多事情,特别是周围的BLE设备多的时候,很是容易致使出现以下错误: 异步

    E/GKI  LINUX(17741): ##### ERROR : GKI exception: GKI  exception(): Task State Table E/GKI LINUX(17741): ##### ide

    E/GKI  LINUX(17741): ##### ERROR : GKI exception: TASK ID [0] task name [BTU] state [1] oop

    E/GKI ui

    LINUX(17741): #####google

    LINUX(17741): ##### ERROR : GKI spa

    exception: TASK ID [1] task name [BTIF] state [1]线程

    LINUX(17741): ##### code

    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() 尽快返回。  [  参考帖子 ] 

  3. 在使用  BluetoothDevice.connectGatt() 或者 BluetoothGatt.connect() 等创建  BluetoothGatt 链接的时候,在任什么时候刻都只能最多一个设备在尝试创建链接。若是同时对多个蓝牙设备发起创建 Gatt 链接请求。若是前面的设备链接失败了,后面的设备请求会被永远阻塞住,不会有任何链接回调。 

    开发建议:若是要对多个设备发起链接请求,最好是有一个同一个的设备链接管理,把发起链接请求序列化起来。前一个设备请求创建链接,后面请求在队列中等待。若是链接成功了,就处理下一个链接请求。若是链接失败了(例如出错,或者链接超时失败),就立刻调用  BluetoothGatt.disconnect() 来释放创建链接请求,而后处理下一个设备链接请求。  [  参考帖子 ] 

  4. 对 BluetoothGatt 操做  (read/write)Characteristic() , (read/write)Descriptor() 和  readRemoteRssi() 都是异步操做。须要特别注意的是,同时只能有一个操做(有些贴这说只能同时有一个 writeCharacteristic() ,这个我并无严格验证),也就是等上一个操做回调(例如  onCharacteristicWrite() )之后,再进行下一个操做。 

    开发建议:把这写操做都封装成同步操做,一个操做回调以前,阻塞主其余调用。  [  参考帖子 ] 

  5. BLE 设备的创建和断开链接的操做,例如 BluetoothDevice.connectGatt() ,  BluetoothGatt.connect() , BluetoothGatt.disconnect() 等操做最好都放在主线程中,不然你会遇到不少意想不到的麻烦。 

    开发建议:对  BluetoothGatt 的链接和断开请求,都经过发送消息到 Android 的主线程中,让主线程来执行具体的操做。例如建立一个  new Handler(context.getMainLooper()); ,把消息发送到这个  Handler中。  [  参考帖子 ] 

  6. 若是你在开发 BLE 应用的时候,有时候会发现系统的功耗明显增长了,查看电量使用状况,蓝牙功耗占比很是高,好像低功耗是徒有虚名。使用  adb bugreport 获取的了系统信息,分析发现一个名叫 BluetoothRemoteDevices 的  WakeLock 锁持有时间很是长,致使系统进入不了休眠。分析源代码发现,在链接 BLE 设备的过程当中,系统会持有 (Aquire) 这个  WakeLock ,直到链接上或者主动断开链接(调用  disconnect() )才会释放。若是BLE设备不在范围内,这个超时时间大约为30s,而这时你可能又要尝试从新链接,这个  WakeLock 有被从新持有,这样系统就永远不能休眠了。 

    开发建议:对BLE设备链接,链接过程要尽可能短,若是链接不上,不要盲目进行重连,否这你的电池会很快被消耗掉。这个状况,实际上对传统蓝牙设备链接也是同样。  [  参考帖子 ] 

  7. Android 做为中心设备,最多只能同时链接 6 个 BLE 外围设备(可能不一样的设备这个数字不同),超过 6 个,就会链接不上了。如今 BLE 设备愈来愈多,其实并不够用,因此在开发的过程当中,须要特别的谨慎使用。

    开发建议:按照须要链接设备,若是设备使用完了,应该立刻释放链接(调用 BluetoothGatt.close() ),腾出系统资源给其余可能的设备链接。  [  参考帖子 ] 

本文只是一些经验之谈,观点也比较琐碎。这里不少问题都看起来是蓝牙协议栈不完善致使的,或许在后面 Android 升级中会修复这些问题,我这里说的可能不适用了。


From: http://www.tuicool.com/articles/aqyyayZ

相关文章
相关标签/搜索