onServicesDiscovered never called while connecting to GATT Server

Something that has been really useful for me is to wait for about 600ms after the connection has been established and then start the service discovery.


BLE on Android can be a little finicky.

Make sure you are calling mBluetoothGatt.discoverServices() on the UI thread.

if(newState == STATE_CONNECTED) {
    Log.d(TAG, "Device connected");
    new Handler(Looper.getMainLooper()).post(new Runnable() {
        @Override
        public void run() {
            boolean ans = mBluetoothGatt.discoverServices();
            Log.d(TAG, "Discover Services started: " + ans);
        }
    });
}

Also try making BluetoothGatt gatt a field variable instead of a local variable.

If you are doing any significant work, try using a library that masks all of the idiosyncrasies so you can focus on the high level logic. https://github.com/Polidea/RxAndroidBle.

Here is an example of how to read a characteristic.

        connectionObservable
                .flatMap(rxBleConnection -> rxBleConnection.readCharacteristic(characteristicUuid))
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(bytes -> {
                    readOutputView.setText(new String(bytes));
                    readHexOutputView.setText(HexString.bytesToHex(bytes));
                    writeInput.setText(HexString.bytesToHex(bytes));
                }, this::onReadFailure);

Or with Java 7 syntax

        connectionObservable
                .flatMap(new Func1<RxBleConnection, Observable<byte[]>>() {
                    @Override
                    public Observable<byte[]> call(RxBleConnection rxBleConnection) {
                        return rxBleConnection.readCharacteristic(characteristicUuid);
                    }
                })
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new Subscriber<byte[]>() {
                    @Override
                    public void onCompleted() {

                    }

                    @Override
                    public void onError(Throwable e) {
                        onReadFailure(e);
                    }

                    @Override
                    public void onNext(byte[] bytes) {
                        readOutputView.setText(new String(bytes));
                        readHexOutputView.setText(HexString.bytesToHex(bytes));
                        writeInput.setText(HexString.bytesToHex(bytes));
                    }
                });