Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
555 views
in Technique[技术] by (71.8m points)

android - onServicesDiscovered never called while connecting to GATT Server

I have a bluetooth headset which is paired with my Nexus 5X (running Android 7.1) and I would like to connect to a GATT Server of the headset. I tried it with the following code:

private BluetoothGattCallback btleGattCallback = new BluetoothGattCallback() {
    @Override
    public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
        Log.d(TAG, "onConnectionStateChange: " + status + ", " + newState);

        if(newState == STATE_CONNECTED) {
            Log.d(TAG, "Device connected");
            boolean ans = gatt.discoverServices();
            Log.d(TAG, "Discover Services started: " + ans);
        }
    }

    @Override
    public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            Log.d(TAG, "Number of Services: " + gatt.getServices().size());
    }
};

public void onDeviceClicked(BluetoothDevice device) {
    BluetoothGatt gatt = device.connectGatt(this, false, btleGattCallback);
    Log.d(TAG, "Connected to GATT: " + gatt.connect());
}

If I click on the headset in my UI onDeviceClicked is called and it comes to this Log output:

<!-- language: lang-none -->
Connected to GATT: true
onConnectionStateChange: 0, 2    // GATT_SUCCESS, STATE_CONNECTED
Device connected
Discover Services started: true

As you can see onServicesDiscovered is never fired. I tried to call connectGatt with TRANSPORT_LE (ref) but then I get a onConnectionStateChange: 133, 0. I also found this question which is why I added the gatt.connect() method as mentioned in answer two.

Do you have any ideas why I don't get the onServicesDiscovered callback?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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));
                    }
                });

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...