Android BLE蓝牙连接要注意的问题

一、运行时问题

发起请求

手机和蓝牙设备建立连接,不论是在哪个进程,哪个线程发起的请求,最终都要丢到系统蓝牙服务进程中去处理。

看到有的文章说在同一个进程中,发起的连接和读写等请求最好都在UI线程里,这种说法我不认同。原因有两点:

1,不论发起请求是在UI线程还是子线程,都只是封装成数据结构丢给系统蓝牙服务进程,这种跨进程通信最终会调到系统蓝牙服务进程的Binder线程池中,然后再由底层的蓝牙框架分发到不同的线程中去处理请求,因此上层调用方在哪个线程对底层来说没太大关系。

2,这种跨进程调用最好不要放在UI线程里,我们知道跨进程调用时调用方会被暂时挂起,直到处理方请求处理完毕。通常来说处理方处理请求会是很快的,如果是耗时的请求就异步处理,这样能保证调用方挂起的时间很短暂。然而当系统负载很重时,这种跨进程通信的调度延时会增加,可能导致UI界面卡顿甚至ANR。

建议的做法是统一分派到一个子线程中去发起所有的请求,即便对于多个设备也是如此,没有必要每个设备一个线程。

请求回调

当系统蓝牙服务处理请求之后,有状态更新时会以回调的方式通知给调用方,比如连接上了,或连接断开了,或数据读到了,或数据写成功了,或设备有数据推送过来了等等。

要注意的是这些回调都不是在UI线程,而是在Binder线程池中。一定要注意到这一点,因为调用方和回调方不在同一个线程,可能存在数据不一致的问题,要么上锁,要么post到同一个线程再处理。

二、异步调用问题

蓝牙的所有请求基本都是异步调用的,对同一个设备,其所有通信过程只能串行,不能并行。如不能同时发起读和写的异步调用,不能同时发起多个character的异步读调用等。必须等到上一个操作的回调之后再发起下一个操作。因此我们需要维护一个任务队列,自动将同一个设备的所有操作串行化。对于多设备的情况,每个设备维护一个任务队列。不过多个设备都共享一个请求分派子线程。

例外的是closeGatt,这个无需放在队列中,当要断开设备连接时,先清空任务队列,再closeGatt。

另外还需对每个调用做超时检查,有时候蓝牙协议栈异常可能收不到回调,如果不做超时检查,后面的所有操作都被堵塞了。对于这些超时的任务,通常是连接出了问题,建议的做法是直接给gatt关掉,下次重新连接的时候重开一个gatt。

三、缓存问题

可能有人想过设备的service既然不变,为什么每次连接都要discover service,不如缓存起来,设备重连时直接用,但实际情况不能这样做。service不能缓存,虽然uuid什么的都没变,但是这些service都会和gatt关联的,如果gatt变了,那service就报废了,对这些service和character做任何读写操作都会出错。所以建议每次连接上时都去discover service,不要缓存。

当设备固件升级后,character可能发生了变化,而系统蓝牙协议栈是不知道的,下次discover service的时候还是返回的旧的缓存,这样读写character可能会失败。解决办法是固件升级后,断开连接再重开一个gatt,并马上刷新一下该设备的缓存。当然,重启蓝牙也会刷新缓存,不过会影响到所有设备。另外有时候discover service服务发现的不全,或者根本发现不了服务,也可以考虑清除一下缓存。 

关于缓存的清除可以参考

how-to-programmatically-force-bluetooth-low-energy-service-discovery-on-android

四、连接释放

设备的GATT句柄在不用时要及时关闭,不然会造成连接泄露,而系统支持的连接句柄数是有限的,如果没记错的话是32个,当达到上限后其它设备就连不了了。注意这是系统全局性的,如果你所在APP占用了过多GATT句柄,其它的APP进程就可能无法成功申请GATT句柄了。因为不论调用方在哪个进程,最终都是由系统服务进程来分配GATT句柄的。

当设备断开连接时,最好closeGatt,而不是diconnect。不要下次复用之前的gatt来reconnect,因为有的手机上重连可能会存在问题,比如重连后死活发现不了service。这种情况下,最好只要断开连接就close gatt,下次连接时打开全新的gatt,这样就可以发现service了。

每个GATT背后都有一套对应的状态机,各种异常基本上除了连接本身之外都是状态机出了问题,因此直接关掉当前GATT,重开一个GATT就能解决大部分问题。就如同解决大部分软件异常,最直接的办法就是重启一样。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,569评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,499评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,271评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,087评论 0 209
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,474评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,670评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,911评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,636评论 0 202
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,397评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,607评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,093评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,418评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,074评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,092评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,865评论 0 196
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,726评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,627评论 2 270

推荐阅读更多精彩内容