BLE Android - 未调用onConnectionStateChange

时间:2016-01-30 15:46:44

标签: java android android-bluetooth bluetooth-lowenergy

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

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

  1. 扫描设备以查找外围设备。
  2. 致电BluetoothDevice#connectGatt(...)。如果连接时间超过1秒,则表示连接“卡住”,因此无法连接,因此再次调用BluetoothDevice#connectGatt(...)。这样做的次数限制为5次。
  3. 使用onConnectionStateChange(...) CONNECTED调用
  4. newState并开始服务发现。
  5. 其余操作没有问题。
  6. 断开连接后BluetoothGatt#close()被调用。
  7. 发生的问题发生在第3点。有时候不会调用onConnectionStateChange(...)。我注意到大多数时候问题都是从特定行为开始的。在BluetoothDevice#connectGatt(...)之后,使用onConnectionStateChange(...) CONNECTED调用newState,但在newStatus DISCONNECTED后再次调用几乎立即(~40毫秒)。由于状态改变的时间很短,我可以推断设备甚至没有尝试建立连接并将状态更改为DISCONNECTED。 问题在以下时间结束:

    1. 20-30秒过去了。在此期间,永远不会调用onConnectionStateChange(...)。问题结束后,onConnectionStateChange(...)将被称为应用尝试连接的次数。例如,如果BluetoothDevice#connectGatt(...)被调用15次,则onConnectionStateChange(...)被调用15次,newState等于DISCONNECTED。这很奇怪,因为在任何连接尝试中都没有将状态更改为CONNECTED。
    2. 该应用程序被杀死并重新开始。
    3. 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应用程序可以始终连接而没有这个问题。

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

      修改<!/强>

      This回答说:

        

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

      所以在这30秒的时间间隔内有一个挂起的连接请求,并在第二个30点超时。这不太可能,但是,有什么办法可以缩短这个时间吗?或者可能有一个我没有看到的连接失败的解释。感谢。

      编辑02/03/2016

      可能有所帮助的新事物。当问题开始时,就是onConnectionStateChange(...)调用newState时,newState等于DISCONNECTED,在{40}之后调用value = float(input("Input your current value: ")) 等于CONNECTED,状态为62 = 0x03E。查看here状态代码表示GATT_CONN_FAIL_ESTABLISH。当我检测到这种状态时,我正在关闭gatt连接,但问题仍然存在。我也试过断开连接。想法?感谢。

3 个答案:

答案 0 :(得分:5)

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

答案 1 :(得分:3)

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

答案 2 :(得分:3)

我不确定你是否还在寻找这个问题的答案。就个人而言,我不建议为低能耗设备制作“用户动作触发的快速和短暂连接”。相反,您可以在connectGatt方法中将autoConnect选项设置为“true”。

device.connectGatt(mContext,true,mGattCallback); [而不是假]

希望它有所帮助!