Android BLE multi-connection
I’m trying to create an app that connects multiple Bluetooth low energy devices and receives notifications from them. I would like to know how to achieve this. Does each connection need a separate thread? Given the asynchronous nature of the API, how can I ensure that the order in which the discovery service and set up notifications is valid. I’m currently using the same structure provided here:
https://developer.android.com/guide/topics/connectivity/bluetooth-le.html This is only set for a single connection. Can I keep this struct by extending the service class in the BluetoothLeService class and binding (bind) to the service. I recently discovered that the Service class is a singleton, so how would I create different instances of my BluetootLeService class and receive broadcasts and register broadcast receivers/receivers to handle changes from the appropriate devices.
Solution
I am wondering how this can be achieved
To implement multiple BLE connections, you must store multiple BluetoothGatt
objects and use them for different devices. You can use Map<>
to store multiple connection objects for BluetoothGatt
private Map<String, BluetoothGatt> connectedDeviceMap;
The onCreate
service initializes the Map
connectedDeviceMap = new HashMap<String, BluetoothGatt>();
Then call device.connectGatt(this, false, mGattCallbacks);
Before connecting to the GATT server Check that the device is already connected.
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(deviceAddress);
int connectionState = mBluetoothManager.getConnectionState(device, BluetoothProfile.GATT);
if(connectionState == BluetoothProfile.STATE_DISCONNECTED ){
connect your device
device.connectGatt(this, false, mGattCallbacks);
}else if( connectionState == BluetoothProfile.STATE_CONNECTED ){
already connected . send Broadcast if needed
}
About BluetoothGattCallback
, if the connection state is CONNECTED, then store objects on the BluetoothGatt
Map
and remove them if the connection state is DISCONNECTED Map
delete
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status,
int newState) {
BluetoothDevice device = gatt.getDevice();
String address = device.getAddress();
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i(TAG, "Connected to GATT server.");
if (!connectedDeviceMap.containsKey(address)) {
connectedDeviceMap.put(address, gatt);
}
Broadcast if needed
Log.i(TAG, "Attempting to start service discovery:" +
gatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i(TAG, "Disconnected from GATT server.");
if (connectedDeviceMap.containsKey(address)){
BluetoothGatt bluetoothGatt = connectedDeviceMap.get(address);
if( bluetoothGatt != null ){
bluetoothGatt.close();
bluetoothGatt = null;
}
connectedDeviceMap.remove(address);
}
Broadcast if needed
}
}
Similarly, onServicesDiscovered(BluetoothGatt gatt, int status)
you have methods on the BluetoothGutt parameter on
the connection object, from which you can get the device BluetoothGatt
and other callback methods such as public void onCharacteristicChanged (BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)
You will get the device form gatt
.
When writeCharacteristic or writeDescriptor is required, get the BluetoothGutt
object from the Map
and call it using the BluetoothGatt
object gatt.writeCharacteristic(characteristic
) gatt.writeDescriptor(descriptor)
is used for different connections.
Do I need a separate thread for each connection?
I don’t think you need to use a separate Thread for each connection. Just run the Service
on a background thread.
Hope this helps.