Java 按顺序连接BluetoothGatt设备的正确方法

Java 按顺序连接BluetoothGatt设备的正确方法,java,android,bluetooth-lowenergy,bluetooth-gatt,Java,Android,Bluetooth Lowenergy,Bluetooth Gatt,我已经实现了蓝牙低能设备扫描逻辑,但我在蓝牙GATT服务使用方面有点困难。我想做的是从Android手机依次连接到我的每个ESP32设备,这样我就可以接收数据,然后继续连接到下一个设备(并断开与上一个设备的连接)。因此,ESP32和Android手机之间只有一个活动连接。ESP32已经过编程,所以如果android手机使用蓝牙GATT连接到它,那么它会发送数据(最多20字节) 真正的困难是理解如何管理这些连接以正确关闭/释放资源 管理这些BluetoothGatt连接的正确/最简单的方法是什么?

我已经实现了蓝牙低能设备扫描逻辑,但我在蓝牙GATT服务使用方面有点困难。我想做的是从Android手机依次连接到我的每个ESP32设备,这样我就可以接收数据,然后继续连接到下一个设备(并断开与上一个设备的连接)。因此,ESP32和Android手机之间只有一个活动连接。ESP32已经过编程,所以如果android手机使用蓝牙GATT连接到它,那么它会发送数据(最多20字节)

真正的困难是理解如何管理这些连接以正确关闭/释放资源

管理这些
BluetoothGatt
连接的正确/最简单的方法是什么?

当发送的数据是
“end”
时,我的实现基本上连接到一个新的设备Gatt服务。问题是,如果一个ESP32设备处于活动状态,则此功能正常。如果有更多的设备处于活动状态,则会发生一些情况,并且无法从Gatt服务接收数据

下面是我实现的一部分(对不起,我不能再减少代码大小了):

1) 我使用BLE扫描仪来发现新设备

private Handler _leScanHandler = new Handler();
private final BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
    @Override
    public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
        final int newRSSI = rssi;
        _leScanHandler.post(new Runnable() {
            @Override
            public void run() {
                addDeviceToListOnLEScan(device, newRSSI);
            }
        });
    }
};
2) 被调用的方法基本上管理
BluetoothGatt
conenctions

public void addDeviceToListOnLEScan(BluetoothDevice device, int rssi) {

    // Gets only user defined devices
    boolean isUserDefinedDevice = _definedDevicesHashMap.containsKey(device.getAddress());
    if (!isUserDefinedDevice) {
        return;
    }

    // Adds device and updates 'LastModifiedTime = Date(System.currentTimeMillis())'
    addOrUpdateDevice(device.getAddress(), _scannedDevices);

    // Called only once on each connect button press to enable gatt operations
    if (!_isInitialConnectionHasBeenMade) {
        _isDataSendingCompleteFromCurrentGatt = true;
        _isInitialConnectionHasBeenMade = true;
    }

    // Sequential BLE device connect/disconnect operations
    if (_isDataSendingCompleteFromCurrentGatt) {

        BluetoothGatt previousGatt = _definedDevicesHashMap(previousAddress);
        if (previousGatt != null) {
            previousGatt.disconnect(); // ?
        }

        BluetoothGatt nextGatt = _definedDevicesHashMap(nextAddress);
        if (/* Checks if 'nextAddress' is in _scannedDevices */
            /* And whether device 'IsActive()' */) {

            if (nextGatt == null) {
                nextGatt = connectToDeviceGattService(nextGatt)     
            }
            else {
                // Do something here ?
            }
            _isDataSendingCompleteFromCurrentGatt = false;  
        }
    }
}
3) 下面是我正在使用的变量/类

private boolean _isDataSendingCompleteFromCurrentGatt = false;
private boolean _isInitialConnectionHasBeenMade = false;
private HashMap<String, BluetoothGatt> _definedDevicesHashMap;
_definedDevicesHashMap.put("ff:ff:9f:c8:c2:93", null);
_definedDevicesHashMap.put("ff:ff:9f:c8:c4:91", null);
...

private HashMap<String, MyBLEDevice> _scannedDevices;

public class MyBLEDevice
{
    private final int deviceInactivityTimeout = 10;
    private String MacAddress;
    private Date _lastModifiedDate;
    public boolean isDeviceActive() {
        // Just gets the time difference (DateNow - lastModified) / 1000 < 10s
    }
}
5) BluetoothGatt的
回调

private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_CONNECTED) {

            // Discover services ?

        } else if (status == BluetoothGatt.GATT_SUCCESS && newState == BluetoothProfile.STATE_DISCONNECTED) {

            // Do nothing ?

        } else if (status != BluetoothGatt.GATT_SUCCESS) {

            // Disconnect from current BluetoothGatt instance? 
            // Also close the connection ?

            _isDataSendingCompleteFromCurrentGatt = true;
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
        enableGattConfigurationCharacteristic();
    }

    @Override
    public void onCharacteristicChanged(BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) {
        _gattServiceHandler.post(new Runnable() {
            @Override
            public void run() {
                handleMessage(Message.obtain(null, MSG_CHARACTERISTIC_CHANGE, characteristic));
            }
        });
    }
};
6) 最后是用于从Gatt回调接收数据的处理程序

private static final int MSG_CHARACTERISTIC_CHANGE = 0;
private Handler _gattServiceHandler = new Handler();
private void handleMessage(Message msg) {
    BluetoothGattCharacteristic characteristic;
    switch (msg.what) {
        case MSG_CHARACTERISTIC_CHANGE: {
            characteristic = (BluetoothGattCharacteristic) msg.obj;
            if (BLELogic.PROPERTY_NOTIFY_CHAR_UUID.equals(characteristic.getUuid())) {

                String notification = BluetoothExtension.getCharacteristicValue(characteristic);
                if (notification.equals("end")) {
                    _isDataSendingCompleteFromCurrentGatt = true;           
                } else {
                    UpdateViewOnGattNotificationSent(notification);
                }
            }
        }
        default:
            return;
    }
}
一开始,我想简化所有逻辑,但在使用BLE/Gatt服务连接时,似乎没有什么简单的地方

简而言之:

要实现多个BLE连接,必须存储多个 BluetoothGatt对象,并将这些对象用于不同的开发。到 存储BluetoothGatt的多个连接对象,可以使用Map

私有映射已连接设备映射

这是一个你可能感兴趣的例子

简而言之:

要实现多个BLE连接,必须存储多个 BluetoothGatt对象,并将这些对象用于不同的开发。到 存储BluetoothGatt的多个连接对象,可以使用Map

私有映射已连接设备映射



谢谢你的回复。是的,我已经看过那个帖子了。虽然,据我所知,他们试图同时连接到多个设备。您是否对所有设备使用相同的
BluetoothGattCallback
?每个
BluetoothGatt
都必须有自己的小世界,在那里它可以生存和死亡,这是我的经验,dunno。是的,我对所有设备只使用一个回调。如果只有一个活动连接,它们是否会冲突或以某种方式影响程序的工作方式?我创建了github项目,显示了这一点,也许它有助于使用单独的回调,我还没有尝试过,我会检查它,谢谢。谢谢回复。是的,我已经看过那个帖子了。虽然,据我所知,他们试图同时连接到多个设备。您是否对所有设备使用相同的
BluetoothGattCallback
?每个
BluetoothGatt
都必须有自己的小世界,在那里它可以生存和死亡,这是我的经验,dunno。是的,我对所有设备只使用一个回调。如果只有一个活动连接,它们是否会冲突或以某种方式影响程序的工作方式?我创建了github项目,显示了这一点,也许它有助于使用单独的回调,我还没有尝试过,我会检查它,谢谢。如果我正确理解您的问题,即使存在多个设备,您也只希望维护一个BLE连接。在一个设备断开连接后,您希望连接到另一个设备,并且只有一个活动连接。是吗?是的,这是我的目标,因为我检查了当多个连接同时处于活动状态时,代码会变得更加复杂。在调用connectToDeviceGattService()之前停止扫描,并仅在设备断开连接后启用扫描。如果(status==BluetoothGatt.GATT_SUCCESS&&newState==BluetoothProfile.STATE_DISCONNECTED){startscanning()}或者如果(status!=BluetoothGatt.GATT_SUCCESS){startscanning()}您的安装程序应该可以正常工作,所以一定有一些bug。“如果更多的设备处于活动状态,则会发生某些情况,并且无法从Gatt服务接收数据……”您能否详细说明一下“某些情况”?哪些步骤有效,哪些步骤失败?你可以添加更多的日志,看看它有多远。您的EnableGattConfiguration特性看起来如何?嗯,它有点不起作用。所以,我想有些事情不起作用了。我到处都在添加日志,但仍然很难理解问题出在哪里。我对
BluetoothAdapter
BluetoothGatt
库有点失望。它们是如此难以使用和理解。。此外,这不再紧迫,因为我找到了使用本地托管的web服务器将数据从ESP32发送到Android的其他方法,数据通过WiFi发送。如果我正确理解了您的问题,那么即使有多个设备广告,您也只想保持一个BLE连接。在一个设备断开连接后,您希望连接到另一个设备,并且只有一个活动连接。是吗?是的,这是我的目标,因为我检查了当多个连接同时处于活动状态时,代码会变得更加复杂。在调用connectToDeviceGattService()之前停止扫描,并仅在设备断开连接后启用扫描。如果(status==BluetoothGatt.GATT_SUCCESS&&newState==BluetoothProfile.STATE_DISCONNECTED){startscanning()}或者如果(status!=BluetoothGatt.GATT_SUCCESS){startscanning()}您的安装程序应该可以正常工作,所以一定有一些bug。“如果有更多设备处于活动状态
private static final int MSG_CHARACTERISTIC_CHANGE = 0;
private Handler _gattServiceHandler = new Handler();
private void handleMessage(Message msg) {
    BluetoothGattCharacteristic characteristic;
    switch (msg.what) {
        case MSG_CHARACTERISTIC_CHANGE: {
            characteristic = (BluetoothGattCharacteristic) msg.obj;
            if (BLELogic.PROPERTY_NOTIFY_CHAR_UUID.equals(characteristic.getUuid())) {

                String notification = BluetoothExtension.getCharacteristicValue(characteristic);
                if (notification.equals("end")) {
                    _isDataSendingCompleteFromCurrentGatt = true;           
                } else {
                    UpdateViewOnGattNotificationSent(notification);
                }
            }
        }
        default:
            return;
    }
}