Totally Disconnect a Bluetooth Low Energy Device
Solution 1
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);
}
}
Solution 2
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
Solution 3
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....
Solution 4
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()
}
}
}
![nilsi](https://i.stack.imgur.com/6Elkl.png?s=256&g=1)
Comments
-
nilsi almost 3 years
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?
-
SoroushA over 8 yearsdo you stop scanning for devices after you connect to the ble device? I had a similar issue which the phone stayed connected to the ble chip even after calling disconnect. The issue was that I never called mScanner.stopScan(mScanCallback) after successful connection.
-
nilsi over 8 yearsThank you but yes I call stopScan upon successful connection.
-
-
nilsi over 8 yearsI am disconnecting before closing, the callback gets called on disconnect. Which means I already disconnected it when calling
close()
? Your answer is only adding a null check to my code? -
Fakher over 8 yearsno no in fact you must call the disconnect method otherwise it just close the Gatt without disconnecting !! just try it
-
Tanasis about 8 yearsDoes
isConnected()
return some kind of a private variable that you track? Can you elaborate more...? Thx! -
nilsi about 8 yearsDon't remember but I think that was just a utility method I made. Checking if
gatt
was null, if so then I was sure there was no connection already. I should also have setgatt
to null inonConnectionStateChange
I think -
Brian Reinhold over 5 yearsThat is not proper behavior by the peer according to the spec. When a peer receives a connection event, it shall stop advertising. Since many BTLE devices behave badly (as does the Android API) as a work-a-round I ignore any received advertisement from an already connected device. I do turn of scanning during connection but once connected I turn it back on. Otherwise you cannot support multiple simultaneous connections.