BLE Android - onConnectionStateChange 未被调用

我在尝试连接到外围设备时遇到问题。有时在 之后不调用回调。我试图实现的是由用户操作触发的快速和短连接。onConnectionStateChange(...)BluetoothDevice#connectGatt(...)

这种情况大约每10次发生1次,没有具体的事先行动。它持续约20到30秒,或直到应用程序被终止并重新打开。我遵循的正常步骤顺序是:

  1. 扫描设备以查找外围设备。
  2. 叫。如果连接时间超过 1 秒,则表示连接“卡住”,因此无法连接,因此再次调用。这是在限制5次尝试的情况下完成的。BluetoothDevice#connectGatt(...)BluetoothDevice#connectGatt(...)
  3. onConnectionStateChange(...)使用 CONNECTED 调用并开始服务发现。newState
  4. 其余操作的执行没有问题。
  5. 断开连接后调用。BluetoothGatt#close()

问题出现在第 3 点。有时不被调用。我注意到,大多数时候问题始于特定行为。调用 后,使用 CONNECTED 调用 ,但几乎紧接着(约 40 毫秒)再次调用 DISCONNECTED。由于状态更改的时间较短,我可以推断出设备甚至没有尝试建立连接并将状态更改为“已断开连接”。问题在以下情况下结束:onConnectionStateChange(...)BluetoothDevice#connectGatt(...)onConnectionStateChange(...)newStatenewStatus

  1. 20-30秒过去了。在此期间从不调用。当问题结束时,称为应用尝试连接的次数。例如,如果被调用 15 次,则调用 15 次,等于 DISCONNECTED。这很奇怪,因为在任何这些连接尝试中,状态从未更改为“已连接”。onConnectionStateChange(...)onConnectionStateChange(...)BluetoothDevice#connectGatt(...)onConnectionStateChange(...)newState
  2. 应用被终止并重新启动。

此错误发生在 SDK18 和 SDK 21 中。

@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
    String deviceName = device.getName();
    if (deviceName == null) return;
    Log.d("BLUETOOTH CONNECTION", "Device found: " + device.getName());
    if (mMode == SCAN_MODE) {
        mListener.deviceFound(device, rssi, scanRecord);
    }
    else {
        mDevices.put(device.hashCode(), device);
        stopScan();
        // Samsung devices with SDK 18 or 19 requires that connectGatt is called in main thread.
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                Log.d("BLUETOOTH CONNECTION", "Executing first device.connectGatt()");
                BluetoothGatt gatt = device.connectGatt(mContext, false, mGattCallback);
                retryIfNecessary(device, gatt);
                mTryingToConnect = true;
            }
        });
    }
}
private void retryIfNecessary(final BluetoothDevice device, final BluetoothGatt gatt) {
    if (isRetryLimitReached()) {
        Log.d("BLUETOOTH CONNECTION", "Try count limit reached");
        finishConnection(gatt);
        mRetryCount = 0;
        mListener.error(TIMEOUT);
        return;
    }
    mRetryCount++;
    mHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            Log.d("BLUETOOTH CONNECTION", "Check if it is frozen.");
            if (isWorking()) {
                Log.d("BLUETOOTH CONNECTION", "Frozen, create new connection.");
                BluetoothGatt gatt = device.connectGatt(mContext, false, mGattCallback);
                retryIfNecessary(device, gatt);
            }
        }
    }, RETRY_INTERVAL_MS);
}
    @Override
    public void onConnectionStateChange(final BluetoothGatt gatt, int status, int newState) {
        Log.d("BLUETOOTH CONNECTION", "On connection state changed. Device: "+ gatt.getDevice().getAddress());
        if (!mConnected && BluetoothGatt.STATE_CONNECTED == newState) {
            Log.d("BLUETOOTH CONNECTION", "Connected");
            mTryingToConnect = false;
            mTryingToDiscoverServices = true;
            mConnected = true;
            gatt.discoverServices();
        }
        else if(BluetoothGatt.STATE_DISCONNECTED == newState) {
            Log.d("BLUETOOTH CONNECTION", "Disconnected and closing gatt.");
            mConnected = false;
            gatt.close();
            if (!mConnectionFinished && mRetryCount == 0) {
                finishConnection(gatt);
            }
        }
    }

我认为外围设备无关紧要,因为iOS应用程序始终可以连接而不会出现此问题。

有什么想法吗?提前致谢。

编辑!

这个答案是这样的:

直接连接的间隔为60ms,窗口为30ms,因此连接完成得更快。此外,一次只能有一个直接连接请求处于挂起状态,并且在 30 秒后超时。onConnectionStateChange() 调用 state=2, status=133 以指示此超时。

因此,在此 30 秒间隔内,有一个挂起的连接请求,并在第二个 30 秒超时。这不太可能,但是,我能做些什么来缩短这个时间吗?或者也许有我没有看到的连接失败的解释。谢谢。

编辑 02/03/2016

可能会有所帮助的新信息。当问题开始时(当在被调用约 40 毫秒后调用时),状态为 62 = 0x03E。在这里看,状态代码意味着GATT_CONN_FAIL_ESTABLISH。当我检测到此状态时,我正在关闭gatt连接,但问题仍然存在。我还尝试断开连接并关闭。想法?谢谢。onConnectionStateChange(...)newState=DISCONNECTEDnewState=CONNECTED


答案 1

如果有人遇到类似的问题,问题最终通过更改外围设备(arduino)使用的BLE芯片来解决。在进行更改之前,我发现的解决方法是在每次连接后关闭并打开BLE。解决方案并不完美,但大大提高了连接率。


答案 2

Android蓝牙需要偶尔回收,当您遇到此时间时,您是否尝试过在设备上重新启动BLE?

这是我用来在奇怪的事情开始发生时重新启动BLE的片段。

static Handler mHandler = new Handler();
public static void restartBle() {
    final BluetoothManager mgr = (BluetoothManager) ApplicationBase.getAppContext().getSystemService(Context.BLUETOOTH_SERVICE);
    final BluetoothAdapter adp = mgr.getAdapter();
    if (null != adp) {
        if (adp.isEnabled()) {
            adp.disable();

            // TODO: display some kind of UI about restarting BLE
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (!adp.isEnabled()) {
                        adp.enable();
                    } else {
                        mHandler.postDelayed(this, 2500);
                    }
                }
            }, 2500);
        }
    }
}

推荐