BLE连接始终调用已断开的操作(GATT配置文件)

6
我建立了一个BLE连接,用于在设备之间发送数据(每10秒钟左右,它们会建立新的连接、发送数据,然后断开连接),通常情况下都能正常工作。然而,在一些分钟之后,设备再也无法连接,并且应该与其他设备连接的设备一直在调用“ACTION_GATT_DISCONNECTED”(此字符串指的是已断开连接的接收器操作)。
在我的接收器中,我有3个相关操作:
@Override
    public void onReceive(Context context, Intent intent) {
        customBluetoothManager = customBluetoothManager.getInstance(context, null, null);
        final String action = intent.getAction();
        Log.d("test", "onReceive");
        if (BluetoothLeService.ACTION_GATT_CONNECTED.equals(action)) {
            Log.d("test", action);
        } else if (BluetoothLeService.ACTION_GATT_DISCONNECTED.equals(action)) {
            Log.d("test", action);
        } else if (BluetoothLeService.ACTION_GATT_SERVICES_DISCOVERED.equals(action)) {
            Log.d("test", action);
            //....
            //Code to send data after services discovered
            //....
        }
    }

因此,在最初几分钟内一切正常。首先调用ACTION_GATT_CONNECTED,然后调用ACTION_GATT_SERVICES_DISCOVERED动作,接着设备发送数据,之后断开连接并释放蓝牙通信通道。

问题是有时候,并不总是在同一时间点(这就是我无法找到任何重现该问题的模式的原因),它会一直循环调用ACTION_GATT_DISCONNECTED,所以通信永远不会建立。

ACTION_GATT_DISCONNECTEDBluetoothGattCallback类的onConnectionSateChange回调中赋值:

@Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            String intentAction;
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(TAG, "Connected to GATT server.");
            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.i(TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
                mBluetoothGatt.close();
            }
        }

我不知道可能是什么问题... 有什么建议吗?

---------- 更新 --------------

使用回调函数更新了连接:

private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) {

                    String name = device.getName();
                    long epoch = System.currentTimeMillis() / 1000;
                    SharedPreferences prefs = context.getSharedPreferences(
                            "epoch", Context.MODE_PRIVATE);
                    long epochStored = prefs.getLong("epoch", 0);

                    if (name != null && name.compareTo(bluetoothDeviceName) == 0 && (epochStored == 0 || epochStored < epoch - Utils.getDelay())) {

                        mac = device.getAddress();
                        mDeviceAddress = device.getAddress();
                        final Intent gattServiceIntent = new Intent(context, BluetoothLeService.class);

                        if (!connected) {
                            Utils.setMessageLog(ac, tv, "Binding service");
                            context.bindService(gattServiceIntent, mServiceConnection, context.BIND_AUTO_CREATE);
                        } else {
                            mBluetoothLeService.connect(mac);
                        }
                    }
                }
            };

连接函数:

public boolean connect(final String address) {
        if (mBluetoothAdapter == null || address == null) {
            Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
            return false;
        }

        if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress)
                && mBluetoothGatt != null) {
            Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                mConnectionState = STATE_CONNECTING;
                return true;
            } else {
                return false;
            }
        }
        final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            Log.w(TAG, "Device not found.  Unable to connect.");
            return false;
        }

        mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
        Log.d(TAG, "Trying to create a new connection.");
        mBluetoothDeviceAddress = address;
        mConnectionState = STATE_CONNECTING;
        return true;
    }

连接成功后,我在接收器中收到一个“SERVICES_DISCOVERED”动作,并通过以下代码写入特征值:
public void sendData() {
        List<BluetoothGattService> listServices = mBluetoothLeService.getSupportedGattServices();

        BluetoothGattService bluetoothGattService = null;
        for (BluetoothGattService gattService : listServices) {
            if (gattService.getUuid().compareTo(myUUID) == 0) {
                bluetoothGattService = gattService;
            }
        }

        if(bluetoothGattService != null) {
            List<BluetoothGattCharacteristic> gattCharacteristics = bluetoothGattService.getCharacteristics();
            ArrayList<BluetoothGattCharacteristic> charas = new ArrayList<BluetoothGattCharacteristic>();

            for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
                if (gattCharacteristic.getUuid().compareTo(myCharUUID)) == 0) {
                    charas.add(gattCharacteristic);
                    boolean status = mBluetoothLeService.writeCharacteristic(gattCharacteristic, Utils.getUserData(context, "id"));
                }
            }
        }
    }

第一次建立蓝牙通信时工作正常。

------------- 第二次更新 --------------

我正在调用close()以释放连接:

@Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            super.onCharacteristicWrite(gatt, characteristic, status);
            disconnect();
            close();
        }

close() function:

public void close() {
        if (mBluetoothGatt == null) {
            return;
        }
        mBluetoothGatt.close();
        mBluetoothGatt = null;
    }

----------- 通过错误日志进行更新 ------------

05-31 11:14:38.581 5897-6100/app D/OCSC: Status: 0
05-31 11:14:38.581 5897-6100/app  D/OCSC: New State: 2
05-31 11:15:08.361 5897-6073/app  D/OCSC: Status: 0
05-31 11:15:08.361 5897-6073/app  D/OCSC: New State: 2
05-31 11:15:35.031 5897-6010/app  D/OCSC: Status: 0
05-31 11:15:35.031 5897-6010/app  D/OCSC: New State: 2
05-31 11:16:08.331 5897-5909/app  D/OCSC: Status: 0
05-31 11:16:08.341 5897-5909/app  D/OCSC: New State: 2
05-31 11:16:36.031 5897-5908/app  D/OCSC: Status: 0
05-31 11:16:36.031 5897-5908/app  D/OCSC: New State: 2
05-31 11:17:08.341 5897-6100/app  D/OCSC: Status: 0
05-31 11:17:08.341 5897-6100/app  D/OCSC: New State: 2
05-31 11:17:38.621 5897-6100/app  D/OCSC: Status: 0
05-31 11:17:38.621 5897-6100/app  D/OCSC: New State: 2
05-31 11:18:08.431 5897-6058/app  D/OCSC: Status: 0
05-31 11:18:08.431 5897-6058/app  D/OCSC: New State: 2
05-31 11:18:38.011 5897-6123/app  D/OCSC: Status: 0
05-31 11:18:38.011 5897-6123/app  D/OCSC: New State: 2
05-31 11:19:13.451 5897-6123/app  D/OCSC: Status: 133
05-31 11:19:13.451 5897-6123/app  D/OCSC: New State: 0

当断开连接问题发生时,我发现通常新状态显示为22或133(只有一次我见过新状态为19)。
D/OCSC: New State: 133
D/OCSC: Status: 0
D/OCSC: New State: 133
D/OCSC: Status: 0
D/OCSC: New State: 133
D/OCSC: Status: 0

D/OCSC: New State: 22
D/OCSC: Status: 0
D/OCSC: New State: 22
D/OCSC: Status: 0
D/OCSC: New State: 22
D/OCSC: Status: 0

btsnoop_hci.log中发现以下错误:

接收到错误响应 - 未找到属性,句柄: 0x0005,句柄: 0x0005(通用访问配置文件:外观)

发送读取类型请求,GATT包含声明,句柄: 0x0006..0x0008

接收到错误响应 - 未找到属性,句柄: 0x0006,句柄: 0x0006(通用属性配置文件)

....

接收到错误响应 - 未找到属性,句柄: 0x0008,句柄: 0x0008(通用属性配置文件:服务更改)

....

接收到错误响应 - 未知属性,句柄: 0x0102,句柄: 0x0102(未知:未知)

....

接收到错误响应 - 无效属性值长度,句柄: 0x0102, 句柄: 0x0102(未知:未知)

Logcat (测试1):

BluetoothGatt: onClientConnectionState() - status=0 clientIf=10
OCSC    : Status: 0
OCSC    : New State: 2
OCSC    : Connected to GATT server.
BluetoothGatt: discoverServices()
BluetoothLeService: Attempting to start service discovery:true
test    : com.example.bluetooth.le.ACTION_GATT_CONNECTED
BluetoothGatt: onClientConnectionState() - status=22 clientIf=8 
BluetoothGatt: onClientConnectionState() - status=22 clientIf=10
BtGatt.GattService: onDisconnected() - clientIf=12
luetoothGatt: onClientConnectionState() - status=22 clientIf=11
BluetoothGatt: onClientConnectionState() - status=22 clientIf=12
OCSC    : Status: 22
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
OCSC    : Status: 22
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
OCSC    : Status: 22
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
OCSC    : Status: 22
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
BluetoothGatt: close()
BluetoothGatt: close()
BluetoothGatt: close()
BluetoothGatt: close()

日志记录(测试2):

BluetoothGatt: onClientConnectionState() - status=133 clientIf=7
OCSC    : Status: 133
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
BluetoothGatt: close()
BluetoothGatt: onClientConnectionState() - status=133 clientIf=7
OCSC    : Status: 133
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
BluetoothGatt: close()
BluetoothGatt: onClientConnectionState() - status=22 clientIf=12
OCSC    : Status: 22
OCSC    : New State: 0
OCSC    : Disconnected from GATT server.
BluetoothGatt: close()

有什么想法吗?

1
你首先如何连接到设备? - Emil
1
更新了代码。使用时期变量来在每个连接之间制造延迟。 - adlagar
1
这不是连接的方式,而是绑定到服务的方式...我正在关注connectGatt调用和与BluetoothGatt对象的交互。 - Emil
1
更新了 Emil。感谢你的帮助!如果你想看更多的代码,问我吧...我快疯了 :( - adlagar
1个回答

0

我怀疑您在完成使用BluetoothGatt对象后没有清理它们。断开连接后,如果您不再希望使用该BluetoothGatt对象连接设备,则必须在对象上调用.close()以释放对象分配的资源。最新的Android版本中,所有应用程序一起使用的最大BluetoothGatt对象数量为32个。

看起来您在代码中覆盖了变量mBluetoothGatt。这样,您将失去引用并且无法再调用close()了...请确保在引用被删除之前始终关闭它。


我已经编辑了我的close()函数的帖子。在该函数内部,我将mBluetoothGatt设置为null。非常感谢您的帮助。 - adlagar
嗯...安卓系统是否会将任何内容打印到logcat中?(如果您删除筛选器以仅显示应用程序的输出)。此外,查看btsnoop_hci.log文件也是不错的选择。 - Emil
更新了更多的数据。我有日志,但是如果我打开文件,它是无法读取的。出现像这样的字符:â.˜Bò]'Wý。我该如何正确地读取这个日志? - adlagar
我刚刚注意到,如果您没有收到onCharacteristicWrite回调,则close()永远不会被调用。如果在写入特征之前连接意外断开,这种情况就会发生。您还应该发布完整的logcat日志,其中应包括一些来自系统的有关BT连接失败原因的信息。 - Emil
尝试将close()移动到onConnectionStateChange中(在断开连接下)。 - Emil
显示剩余10条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接