(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()
),腾出系统资源给其余可能的设备链接。 [ 参考帖子 ]