Difference between close() and disconnect()?
Asked Answered
L

2

58

Android Bluetooth Low Energy API implements 1 method to connect to the device connectGatt() but 2 methods to close the connection disconnect() and close().

Documentation says:

  • disconnect(): Disconnects an established connection, or cancels a connection attempt currently in progress.

  • close(): Application should call this method as early as possible after it is done with this GATT client.

The source code of BluetoothGatt.java shows that close() unregisters the application and disconnect() disconnect the client. However it does not say what that actually means. I mean, if there is only 1 way to connect to the client, why there are 2 ways to close/disconnect the connection?

Leviathan answered 16/4, 2014 at 13:3 Comment(1)
I guess Close means you will not longer use Gatt objectBidet
F
96

With disconnect() you can later call connect() and continue with that cycle.

Once you call close() you are done. If you want to connect again you will have to call connectGatt() on the BluetoothDevice again; close() will release any resources held by BluetoothGatt.

Faculty answered 14/5, 2014 at 14:11 Comment(11)
Super helpful- was only calling disconnect() and kept running out of BT interfaces preventing any new connections. Calling close() prevents this.Trochal
Whenever I use disconnect() or close() the callback method onConnectionStateChange never get called indicating STATE_DISCONNECTED.Witte
close() won't get a call to onConnectionStateChange, but disconnect() should. Are you sure you were really connected when you called disconnect()?Faculty
Can I call close(), without calling disconnect()? And will onConnectionStateChange be called in the case?Bib
After calling disconnect() and close() the onCharacteristicChanged() event keeps firing. Does anybody have a solution for this?Watford
@AlexanderFarber you can call close() without disconnect() but you won't get an onConnectionStateChange callback in my experience.Faculty
@Watford My thought is that you probably have multiple peripherals connected and are getting callbacks for the other peripherals, or you disconnected and closed not what you thought you did.Faculty
@DouglasJones Thanks for replying. I am sure I only have a single peripheral connected. I am also sure I only call mBluetoothGatt = device.connectGatt() a single time.Watford
So far, I've only used close() instead of both. But, I've just discovered on a Nexus 6P running Android 7.0, that if I call close() on a device that is currently pending to be connected, but not connected yet, the smartphone still reconnects to the device as soon as it becomes visible again...Basketry
disconnect() does not result in an onConnectionStateChange() if the connection had not already been established.Britteny
I have also struggled with inconsistent behaviors. If you call gatt.close(), the next time you connect to the same device, you will need to redo service discovery.Bonded BTLE devices are not supposed to do that.A bonded peer knows who you are (both for pairing and whether or not characteristics have been enabled) and can (by spec) send any data immediately. It will assume that you know its services. If you have done a gatt close, you wont know its services and may lose that data. I do not know what Android does down low, but working with embedded low level stacks this is definitely the case.Guitarfish
R
15

Here is some food for thought:

As long as you have not called close on the Gatt, you can still try to connect to it, or discover. So when I try to discover services for a machine, I will usually run a thread or runnable that makes the request to connect to the machine for a certain period of time.

The first attempt with a machine connection, will return a BluetoothGatt object that you can later use to try to discover the services for the BluetoothDevice object. It seems pretty easy to connect, but much harder to discover the machine servces.

mBluetoothGatt = machine.getDevice().connectGatt(this, false, mGattCallback);

So in my thread / runnable, I will check to see if the BluetoothGatt is null. If it is, I will call the above line of code again, else I will attempt to discover the BluetoothGatt services as such.

mBluetoothGatt.discoverServices();

Oh, and I ALWAYS make sure to call BluetoothAdapter.cancelDiscovery() before any attempt at connecting of discovering the service.

mBluetoothAdapter.cancelDiscovery();

Here is a method is use to connect in my runnable etc:

public void connectToMachineService(BLEMachine machine) {
    Log.i(SERVICE_NAME, "ATTEMPTING TO CONNECT TO machine.getDevice().getName());

    mBluetoothAdapter.cancelDiscovery();

    if(mBluetoothGatt == null)
        mBluetoothGatt = machine.getDevice().connectGatt(this, false, mGattCallback);
    else
        mBluetoothGatt.discoverServices();
}

Lastly, make sure that you close out any BluetoothGatt objects that you have connected to. It appears that Android can handle five BluetoothGatt objects before it starts saying "unable to connect to Gatt server" or other something like that.

On every BluetoothGatt that I create, I will call close on it then broadcast an update stating the connection is closed. It seems that there are a lot of times where the BluetootGatt will not respond with a state change when it becomes disconnected. My method of closing the BluetoothGatt goes something like this. I leave the method open up for the Activity to call the service and disconnect if a machine becomes non - responsive and the disconnect state is not called.

public void disconnectGatt(BluetoothGatt gatt) {
    if(gatt != null) {
        gatt.close();
        gatt = null;
    }

    broadcastUpdate(ACTION_STATE_CLOSED);
}
Ranchman answered 28/3, 2015 at 2:9 Comment(1)
It is a little bit confusing that you call the method disconnectGatt when you actually call close() instead of disconnect().Dhahran

© 2022 - 2024 — McMap. All rights reserved.