[Bluetooth]: android 平台上BLE连接流程之优化方案

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/teaspring/article/details/77200688

  这是一篇关于之前工作成果的补记。我之前在一家可穿戴设备公司工作,主要工作之一是帮助改进和维护本司的android手机App和本司可穿戴设备(下文简称设备)之间蓝牙通信性能。曾经有一个性能问题困扰了公司很久,就是android手机app和设备之间的(蓝牙)同步成功率很低。相比于iOS手机App和所有设备之间轻松90%+的同步成功率,我们的Android App和各种设备的同步成功率仅仅70%~80%,GoogleStore上面用户对于我们app的差评一半以上跟“设备难以同步”有关。 于是公司决心彻底解决这个问题,我被征调以技术攻关。在经过了不断的尝试后,我们终于比较圆满的解决了这个问题。

  首先当然是分析问题。我们对android用户同步失败的具体环节在代码里做了追踪,分析了至少前后半年的数据。我们发现在所有失败原因里,连接失败大约占六到七成,其余的包括扫描超时,连接参数设置失败,蓝牙读取文件失败等等。所以,我们的重点自然是蓝牙连接失败。在网上能够搜到有关Android平台上蓝牙性能不好的很多帖子,基本没有形成立竿见影的解决方案。我只好去看代码,反复阅读我们自己App调用蓝牙的代码,以及android.bluetooth API的实现代码。android蓝牙调用连接的示例代码很简单,扫描获取一个BluetoothDevice 后,调用它的connectGatt()方法,会返回一个BluetoothGatt。之后这个连接上的所有操作,包括连接状态变化,关闭连接,读写文件等,都在这个BluetoothGatt上操作。

public class BluetoothDevice {
...
public BluetoothGatt connectGatt(Context context, boolean autoConnect, BluetoothGattCallback callback)
}
我注意到我们App的旧代码中也有对于初次连接失败的处理,它调用了BluetoothGatt.connect()

public class BluetoothGatt {
...
public boolean connect()
}
也就是直接在同样一个BluetoothGatt上继续再发起一次连接。可惜我们的追踪代码显示,这里的尝试重连在实际中的成功率非常之低,近乎无效。 显然我们面临的问题,现在变成了如何设计一个性能更好的连接(重连)逻辑。

  第一处引起我怀疑的就是旧代码中的重连函数调用。基于以前在网络编程方面的经历,我觉得BluetoothGatt的行为和TCP/IP的socket很像。socket在通信信道的两端各有一个,如果有异常发生,那么一方就关闭自己的socket,对端也会相应关闭socket。在C/S架构下,client向server重新发起连接,server收到后创建一个新的socket进行通信。所以,我觉得在每次重连时,应该使用一个全新的BluetoothGatt, 即调用BluetootDevice.connectGatt(Context, boolean, BluetoothGattCallback),而不是继续使用旧的BluetoothGatt.connect()。

  接着,考虑到蓝牙连接失败在代码形式上分两种,要么是callback迟迟无返回导致超时,要么是callback返回错误结果。这样我们需要一个蓝牙连接成功耗时的经验值。 于是我们写了一个android上的小工具,反复向设备发起连接,建立连接后简单读取信息,关闭连接,再重连。基于重复多次的实验中重新成功连接的耗时分布,得到我们需要的连接耗时经验值。

  另外,我们在网上搜到了一些帖子,建议Android上在蓝牙关闭一个旧连接,发起一个新连接之间,最好留出一定的延时。我们也把这项参数加入了测试工具中,反复实验不同时间间隔下重连的成功率。

综合以上的思路,我们得到了如下的蓝牙重连逻辑:


新的蓝牙连接逻辑包括:在整个connect()方法内部,设有一个最多内部重连次数的参数,和一个总运行时间的参数,两参数均可配置;在每次内部尝试连接时,首先更新BluetoothGatt对象;在需要关闭一个蓝牙连接时,先“断开”,再“关闭”;在每次对BluetoothGatt连接,(蓝牙)握手,断开的单独调用中,都添加了超时控制。

  当然,在实际运行中,还会有一些事先没想到的情况。比如,internalConnect()如果当次连接成功后,如何防止connectTimer在唤醒后的干扰?是去立即终止这个timer呢,还是别的办法? 这个问题留给读者自己去思考吧。

结局:很幸运,这个解决方案在上线后效果出乎意料的好。仅仅因为这一版改动,我们的Android设备(蓝牙)同步成功率就上升到90%以上,终于能和iOS设备的同步成功率持平了,Thank Godness!

猜你喜欢

转载自blog.csdn.net/teaspring/article/details/77200688