Android ble蓝牙问题
(1)蓝牙回调
安卓4.4的蓝牙回调是在异步线程中(不在主线程),若要在蓝牙回调中执行更新界面的操作,记得切换到主线程去操作
(2)三星手机兼容性问题connectGatt()
方法在某些三星手机上只能在UI线程调用。
备注:三星的手机是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设备
(4)连接不断开的问题
别的BLE程序非法保留连接的设备可能会导致连接不能断开
(5)异步问题
读写Characteristic、Descriptor等几乎所有BLE操作结果都为异步返回,若不等待上一次操作结果返回就执行下一次操作,很可能导致操作失败或者操作无效。onDescriptorWrite()
返回的线程与写入线程为同一个线程,别的操作一般在不同的线程回调。
(6)设备缓存
Android会对连接过的BLE设备的Services进行缓存,若设备升级后Services等有改动,则程序会出现通讯失败。此时就得刷新缓存,但是刷新缓存的方法并没有开放,这里只能使用反射来调用BluetoothGatt
类中的refresh()
方法:
- try {
- Method localMethod = mBluetoothGatt.getClass().getMethod("refresh");
- if (localMethod != null) {
- return (Boolean) localMethod.invoke(mBluetoothGatt);
- }
- } catch (Exception localException) {
- Log.e("refreshServices()", "An exception occured while refreshing device");
- }
(7)扫描设备startLeScan(UUID[], BluetoothAdapter.LeScanCallback)
在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 : GKI
exception: 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()
),腾出系统资源给其他可能的设备连接。 [ 参考帖子 ]
Android ble蓝牙问题的更多相关文章
- Android ble 蓝牙4.0 总结
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- Android ble 蓝牙4.0 总结一
本文介绍Android ble 蓝牙4.0,也就是说API level >= 18,且支持蓝牙4.0的手机才可以使用,如果手机系统版本API level < 18,也是用不了蓝牙4.0的哦 ...
- Android BLE蓝牙详细解读
代码地址如下:http://www.demodashi.com/demo/15062.html 随着物联网时代的到来,越来越多的智能硬件设备开始流行起来,比如智能手环.心率检测仪.以及各式各样的智能家 ...
- Android BLE 蓝牙编程(一)
最近在研究这个,等我有时间来写吧! 终于在端午节给自己放个假,现在就来说说关于android蓝牙ble的 最近的学习成果吧!! 需要材料(写个简单教程吧--关于小米手环的哦!嘿嘿) Android 手 ...
- android ble蓝牙开发略解
Android 蓝牙4.0开发 1. 权限和相关属性 “android:required="true"表示apk只有在具有bluetooth_le属性的系统里运行,这个4.3之前 ...
- Android ble蓝牙使用注意
以下均为自己在Android ble开发项目中遇到的问题 1.尽量不要在BluetoothGattCallback里面的回调函数中执行读写通知操作,最多一个,因为例如在onServicesDiscov ...
- Android BLE 蓝牙开发——扫码枪基于BLESSED
一.蓝牙模式HID与BLE 当扫码枪与手机连接时,通常采用的是蓝牙HID(Human Interface Device)模式.本质上是一个把扫码枪作为一个硬件键盘,按照键盘协议把扫码后的结果逐个输入到 ...
- Android BLE 蓝牙低功耗教程,中央BluetoothGatt和周边BluetoothGattServer的实现
http://blog.csdn.net/wave_1102/article/details/39271693 分类: Android(105) 作者同类文章X Android4.3 规范了BLE的A ...
- Android BLE 蓝牙编程(四)
接上篇,我们已经实现了短震,长震的功能了- 现在我们需要实现点击后一直震动的功能 开始我的想法是再循环中不断执行write方法,然而这个办法行不通. 系统会报错. 那要如何实现这个想法呢?其实很简单, ...
随机推荐
- 通过Visualizing Representations来理解Deep Learning、Neural network、以及输入样本自身的高维空间结构
catalogue . 引言 . Neural Networks Transform Space - 神经网络内部的空间结构 . Understand the data itself by visua ...
- DirectX11 With Windows SDK--16 流输出阶段
前言 在上一章,我们知道了如何使用几何着色器来重新组装图元,比如从一个三角形分裂成三个三角形.但是为了实现更高阶的分形,我们必须要从几何着色器拿到输出的顶点.这里我们可以使用可选的流输出阶段来拿到顶点 ...
- Python系列之 - 前端总结
1. python序列化: 字符串 = json.dumps(对象) 对象->字符串 对象 = json.loads(字符串) 字符串->对象 Javascript: 字符串 = JSON ...
- js 数字前自动补零
num为传入的数字,n为需要的字符长度 return (Array(n).join(0) + num).slice(-n); 例如 我想返回两位数 输入6 然后返回06 就可以这样写: return ...
- 通过命令修改mysql的提示符
在cmd窗口操作mysql数据库的时候,前面的提示符永远都是mysql>,这个提示符可以通过命令修改. 在登录mysql时修改: mysql -uroot -p --prompt 提示符 登录后 ...
- @ReponseBody返回的json中文乱码-遁地龙卷风
我在mvc配置文件中加上下面这个配置就好了 <mvc:annotation-driven></mvc:annotation-driven>,需要在开头引用如下命名空间xmlns ...
- redux知识点
1.关于传参 点击跳转 两种 动态路由 url 但是取值需要自己处理 关于动态跳转(js执行跳转) 关于异步加载组件 创建loadable app.js中 在 要加载的异步组件中 (这样接收参数不 ...
- ubuntu 32/64 bit
https://askubuntu.com/questions/454253/how-to-run-32-bit-app-in-ubuntu-64-bit how to run 32-bit app ...
- 【原创】大数据基础之Spark(8)Spark中Join实现原理
spark中join有两种,一种是RDD的join,一种是sql中的join,分别来看: 1 RDD join org.apache.spark.rdd.PairRDDFunctions /** * ...
- Windows平台下结合 tortoiseSVN 和 VisualSVN Server 搭建SVN服务器并实现 web 站点同步
1. tortoiseSVN 关于 tortoiseSVN 的安装使用详见博文 TortoiseSVN的安装及其简单使用. 2. VisualSVN Server 关于 VisualSVN Serve ...