I connect to a BLE device with the connectGatt()
method in Android. This works great.
When I disconnect I use the following:
private void disconnectDevice() {
gatt.disconnect();
}
When I receive the callback I do a close.
private BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
switch (newState) {
case BluetoothProfile.STATE_CONNECTED:
Log.d("BLED-GATT", "STATE_CONNECTED");
setUIConnectionStatus("Discover services on device...", Color.YELLOW);
checkEnableAddButton(simpleTrackEditText.getText().toString());
gatt.discoverServices();
break;
case BluetoothProfile.STATE_DISCONNECTED:
Log.d("BLED-GATT", "STATE_DISCONNECTED");
setUIConnectionStatus("Not Connected!", Color.RED);
gatt.close();
break;
default:
Log.d("BLED-GATT", "STATE_OTHER");
}
}
}
This is executed and I can no longer control the device after calling disconnectDevice()
. The device itself seems to think that it is still connected since I cant put it in broadcasting visibility mode (which happens if it already has a connection). However, if I kill the application and open it again then I can set the device in broadcasting mode. This tells me the app was not properly disconnected.
Any idea what I missed here?
Users can disable system-level Bluetooth background scanning by going to Settings > Security & Location > Location > Scanning and disabling the toggle for Bluetooth scanning. This does not affect BLE scanning for location or local devices.
Location Permission is mandatory on Android Yes, we were as surprised as you are. Bluetooth is required to setup, update and sync your FitBark device. In 2019, Android made it mandatory for any app to have location permissions in order to work with Bluetooth devices.
Android provides built-in platform support for Bluetooth Low Energy (BLE) in the central role and provides APIs that apps can use to discover devices, query for services, and transmit information. Common use cases include the following: Transferring small amounts of data between nearby devices.
The problem was that I during scanning was connecting to the same device multiple times causing my application to have many connections open at the same time. Adding !isConnected()
solved the problem:
/**
* Connects to the device. Does nothing if already connected.
* @param macAddress the address of the device.
*/
private void connectDevice(String macAddress) {
if (isConnected()) {
return;
}
device = bluetoothAdapter.getRemoteDevice(macAddress);
if (device == null) {
showToast("Device not available");
} else {
showToast("Connecting...");
gatt = device.connectGatt(this, true, gattCallback);
}
}
That's totally logic because you are not disconnecting before closing Gatt.
public void disconnect() {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return;
}
mBluetoothGatt.disconnect();
}
try to call this method before closing your GATT
I experienced same problem and I found two possible root cause as follows: 1. Was same as @nilsi answer, connect to the same device more than once in one scanning. → solved by lock & List 2. connect to the device in one scanning and didn't get onConnectionStateChange, than I scanned again, it resulted in second connection to the same device. → solved by keeping BluetoothGatt object when I call device.connectGatt(), and call object.disconnect(), object.close() before scanning.
My test phone is 4 years old so sometimes it needs more than 20 seconds to return onConnectionStateChange....
As previously stated, the problem is caused by calling connectGatt multiple times. Each one of those calls create a new BluetoothGatt instance and they are all kept alive, while you have only the last one. Given the fact that sometimes it is needed to call connectGatt multiple times, I just keep all the instances that it returns and call disconnect/close on all of them when I'm done. This fixed the disconnection issue instantly
private val gattInstances = LinkedList<BluetoothGatt>()
fun connect() {
bluetoothGatt = device?.connectGatt(
context,
false, gattCallback, TRANSPORT_LE
)
bluetoothGatt?.let { gattInstances.add(it) }
}
fun finish() {
bluetoothGatt?.close()
while (gattInstances.isNotEmpty()) {
gattInstances.pop().apply {
disconnect()
close()
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With