在连接到GATT服务器时从未调用过onServicesDiscovered

时间:2017-01-02 23:33:44

标签: android bluetooth bluetooth-lowenergy

我有一个蓝牙耳机,它与我的Nexus 5X(运行Android 7.1)配对,我想连接到耳机的GATT服务器。我用以下代码尝试了它:

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

如果我点击我的用户界面onDeviceClicked中的耳机,则会调用此日志输出:

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

正如您所见,onServicesDiscovered永远不会被解雇。我尝试使用connectGattref)致电TRANSPORT_LE但我得到了onConnectionStateChange: 133, 0。我还发现this question这就是为什么我添加了答案二中提到的gatt.connect()方法。

你有什么想法我没有得到onServicesDiscovered回调吗?

6 个答案:

答案 0 :(得分:7)

Android上的BLE可能有点挑剔。

确保在UI线程上调用mBluetoothGatt.discoverServices()。

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

同时尝试将BluetoothGatt gatt作为字段变量而不是局部变量。

如果您正在进行任何重要工作,请尝试使用掩盖所有特性的库,以便您可以专注于高级逻辑。 https://github.com/Polidea/RxAndroidBle

以下是如何阅读特征的示例。

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

或使用Java 7语法

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

答案 1 :(得分:6)

对我来说真正有用的东西是在建立连接后等待大约600ms,然后开始服务发现。

答案 2 :(得分:0)

这可能会有所帮助

我将分两步解释:连接和发现服务

<强>连接: 从mainthread连接

将自动重新连接设置为false

如果Version大于或等于M,请设置Tranposrt类型

否则直接使用反射并正确处理

Handler(applicationContext.mainLooper).post {
                    Log.d(TAG, " Post is called inside mainlooper")
                    mBluetoothGatt = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                        Log.d(TAG, " Is Or Greater than M $mBluetoothDevice")
                        mBluetoothDevice!!.connectGatt(this, false,
                                onGhattListener, TRANSPORT_LE)
                    } else {
                        Log.d(TAG, " Less than M")
                        try {
                            Log.d(TAG, " Trying TRANPORT LE with reflection")
                            val m = mBluetoothDevice!!.javaClass.getDeclaredMethod("connectGatt", Context::class.java, Boolean::class.javaPrimitiveType, BluetoothGattCallback::class.java, Int::class.javaPrimitiveType)
                            m.isAccessible = true
                            val transport = mBluetoothDevice!!.javaClass.getDeclaredField("TRANSPORT_LE").getInt(null)
                            m.invoke(mBluetoothDevice, this, false, onGhattListener, transport) as BluetoothGatt
                        } catch (e: Exception) {
                            e.printStackTrace()
                            Log.d(TAG, " Catch to call normal connection")
                            mBluetoothDevice!!.connectGatt(this, false,
                                    onGhattListener)
                        }
                    }
                    Log.d(TAG, "mBluetooth gatt is $mBluetoothGatt")
                    mBluetoothGatt?.let {
                        refreshDeviceCache(mBluetoothGatt!!)
                    }
                }

disover服务:在onGhattListener中,如果设备从主线程连接discoverServices()

override fun onConnectionStateChange(gatt: BluetoothGatt, status: Int,
                                         newState: Int) {
        Log.d(TAG, "onConnectionStateChange $gatt and status $status and newstate $newState")
        when (newState) {
            BluetoothGatt.STATE_CONNECTED -> {
                Handler(Looper.getMainLooper()).post {
                    gatt.discoverServices()
                }
            }
            BluetoothGatt.STATE_DISCONNECTED -> {

            }
            BluetoothGatt.STATE_CONNECTING -> {

            }
            BluetoothGatt.STATE_DISCONNECTING -> {

            }
        }
    }

这可能会解决您的问题

使用反射调用刷新方法

fun refreshDeviceCache(gatt: BluetoothGatt): Boolean {
    try {
        val localMethod = gatt.javaClass.getMethod("refresh")
        if (localMethod != null) {
            return localMethod.invoke(gatt) as Boolean
        }
    } catch (localException: Exception) {
        Log.e(TAG, "An exception occured while refreshing device")
        localException.printStackTrace()
    }
    return false
}

答案 3 :(得分:0)

实际上,我通过多次执行mBluetoothGatt.discoverServices()方法(10次以上)来解决此问题,

    int i = 10;
    while (i > 0)
    {
        if (!mIsBLE_Finded)  //如果服务发现失败,继续执行discoverServices方法
        {
            i--;
            mBluetoothGatt.discoverServices();
            System.out.println("BLEService-->" + "尝试次数:" + i);
        }
        else //在10次的尝试中,存在某次服务发现成功了
        {
            i = -1;
        }
    }

答案 4 :(得分:0)

有同样的问题,但仅等待600毫秒是不够的。这可能是由于使用了BLE模块。我通过调用方法解决了问题

discoverServices(); 

致电后

device.connectGatt(this,false,gattCallback)

我基本上只是每5秒钟调用一次DiscoverServices(这是任意选择的)

private void discoverServices() {
    if(!gattConnected) { //just a boolean
        new Handler(Looper.getMainLooper()).post(new Runnable() {
            @Override
            public void run() {
                gatt.discoverServices();
            }
        });
        new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
            @Override
            public void run() {
                discoverServices();
            }
        }, 5000);
    }
}

在我的gattCallback的onServicesDiscovered(...)方法中,将gattConnected设置为true。 这对我有用。

答案 5 :(得分:0)

我也遇到了同样的问题。 在 onStart() 方法中开始扫描。它对我有用

之前我开始对 onCreate 方法进行扫描。这就是为什么它对我不起作用