添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
仗义的伏特加  ·  502 Bad Gateway ...·  10 月前    · 
飞奔的篮球  ·  HttpClient ...·  1 年前    · 

这里声明一下,这篇文章仅仅针对有一定蓝牙开发基础的同学。

Android BLE开发是个大坑, 连接很不稳定。 多次连接外围设备时, 就会出现连接失败的情况。 观察日志发现 onClientConnectionState() 方法经常出现133 的错误码。

1、 为什么会出现 133的错误码

  • gatt.close()没有调用,资源没有释放导致连接失败
  • 频繁尝试建立连接
  • 系统对Ble最大的连接数量是有限制的,一般最大的连接数量为6, 超过这个限制就会出现133错误码
  • BLE硬件模块问题
  • 如何解决?

    2、 GATT每次连接前, close之前的资源

        // 全局gatt
        private BluetoothGatt mGatt;
        private void connect(BluetoothDevice device, BluetoothGattCallback callback) {
            // 释放上次gatt连接资源
            close();
            if (SdkUtil.isAtLeastM_23()) {
                mGatt = device.connectGatt(ViotSDK.getInstance().getBaseContext(), false, callback, BluetoothDevice.TRANSPORT_LE);
            } else {
                mGatt = device.connectGatt(ViotSDK.getInstance().getBaseContext(), false, callback);
        // 释放上次gatt连接资源
        public void close() {
            if (mGatt != null) {
                mGatt.disconnect();
                mGatt.close();
                mGatt = null;
    

    3、清理Gatt缓存

    在重连的时候先将Gatt缓存进行清理:

        public boolean refreshDeviceCache() {
            try {
                VLog.d(TAG, "clear gatt cache");
                BluetoothGatt localBlueToothGatt = mBluetoothGatt;
                Method localMethod = localBlueToothGatt.getClass().getMethod("refresh", new Class[0]);
                if (localMethod != null) {
                    localMethod.setAccessible(true);
                    Boolean bool = ((Boolean) localMethod.invoke(localBlueToothGatt, new Object[0])).booleanValue();
                    localMethod.setAccessible(false);
                    return bool;
            } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
                e.printStackTrace();
            return false;
    

    然后进行close操作:

        mBluetoothGatt.close();
        mBluetoothGatt = null;
    

    4、 出现133错误码时, 进行重试策略

    在Gatt连接的回调中,如果连接失败,并且错误码是133时,进行重试连接

        // 重试连接三次
        private static int GATT_CONNECT_RETRY_MAX_COUNT = 3;
        private int retryCount = 0;
        private class BleCallback extends BluetoothGattCallback {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                super.onConnectionStateChange(gatt, status, newState);
                if (BluetoothGatt.GATT_SUCCESS == status) { // gatt连接成功
                } else { // gatt连接失败
                    // 连接失败需要释放资源
                    close();
                    if (status == 133 && retryCount < GATT_CONNECT_RETRY_MAX_COUNT) { // 133错误码重试
                        connect(deviice, callback);
    

    由于设备 Rom是公司系统组自己定制的, 所以开关蓝牙的操作是有权限的。 我们可以在重试的过程中, 对设备蓝牙进行重启,更彻底的释放蓝牙连接。

        // 重试连接三次
        private static int GATT_CONNECT_RETRY_MAX_COUNT = 3;
        prvate int retryCount = 0;
        private Handler handler = new Handler(Looper.myLooper());
        private class BleCallback extends BluetoothGattCallback {
            @Override
            public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
                super.onConnectionStateChange(gatt, status, newState);
                if (BluetoothGatt.GATT_SUCCESS == status) { // gatt连接成功
                } else { // gatt连接失败
                    // 释放资源
                    close();
                    if (status == 133 && retryCount < GATT_CONNECT_RETRY_MAX_COUNT) {
                        if (BluetoothUtil.switchBlueState(false)) { // 关闭蓝牙
                            handler.postDelayed(() -> {
                                if (BluetoothUtil.switchBlueState(true)) { // 5s后,开启蓝牙
                                    handler.postDelayed(new Runnable() { // 5s后重试连接设备
                                        @Override
                                        public void run() {
                                            connect(deviice, callback);
                                    }, 5000);
                                } else {
                                    // 重新打开蓝牙失败
                                    connectDeviceError();
                            }, 5000);
                        } else {
                            // 关闭蓝牙失败
                            connectDeviceError();
            private void connectDeviceError() {
    

    蓝牙操作类BluetoothUtil

    public class BluetoothUtil {
        private static final String TAG = BluetoothUtil.class.getSimpleName();
         * 切换蓝牙开关状态
        public static boolean switchBlueState(boolean isOpen) {
            BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
            boolean suc;
            if (isOpen) {
                suc = adapter.enable();
                Log.d(TAG, "open blue suc :" + suc);
            } else {
                suc = adapter.disable();
                Log.d(TAG, "close blue suc :" + suc);
            return suc;
    

    5、 FastBLe

    地址:github.com/Jasonchenli…

    FastBLe 是一个优秀的BLE开源库,在GitHub有4.4K Star, 支持重连机制,连接设备较稳定。

    6、 总结

    经过多次优化, 发现并不能完全杜绝133的错误码的出现,只能减少133的出现。
    这个问题也和机型有关, 我尝试的小米连接较稳定, oppo经常出现。在Ble开发中,容易遇到。还是需要谷歌在协议层, 设备厂商在硬件层进行优化。 开发能做的是尽可能的提高Ble连接的稳定性。
    大家如果有更好的办法, 欢迎在评论区讨论

    stackoverflow.com/questions/2…

    medium.com/@martijn.va…

    www.zhihu.com/question/24…

    github.com/Jasonchenli…

    分类:
    Android