Android BLE快速连接和断开连接以读取1个特征。有些BLE设备在快速连接断开连接后停止播放

问题描述:

我正在尝试编写和扫描BLE设备的Android应用程序,以及何时发现某些具有命名方案的设备连接到它并读取特征(用户定义的名称为该设备)然后立即断开连接。然后它会将设备显示在列表中,并找到任何其他设备并读取用户定义的名称。然后用户可以选择一个设备连接到(或多个设备)并连接到它并从中传输数据。Android BLE快速连接和断开连接以读取1个特征。有些BLE设备在快速连接断开连接后停止播放

继续发生的问题是在获取用户定义的名称并断开连接后,BLE设备停止播放,并且当我扫描或在读取用户定义的名称后尝试连接时,我无法再找到它并断开连接。

这是与Android BLE栈的问题,还是需要增加更多的延迟(我已遍及我使用bluetoothservice 100个毫秒的延迟)

这是我在服务中使用的部分代码

public boolean initialize() { 

    Log.i(TAG, "Initializing"); 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    if (mBluetoothManager == null) { 
     mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE); 
     if (mBluetoothManager == null) { 
      Log.e(TAG, "Unable to initialize BluetoothManager."); 
      return false; 
     } 
    } 

    mBluetoothAdapter = mBluetoothManager.getAdapter(); 
    if (mBluetoothAdapter == null) { 
     Log.e(TAG, "Unable to obtain a BluetoothAdapter."); 
     return false; 
    } 


    mReadyToWrite = true; 
    mReadyToRead = true; 
    mReady = true; 
    mCharacteristicWriteQueue = new ArrayDeque<BluetoothGattCharacteristic>(); 
    mCharacteristicReadQueue = new ArrayDeque<BluetoothGattCharacteristic>(); 
    mDescriptorWriteQueue  = new ArrayDeque<BluetoothGattDescriptor>(); 
    mDescriptorReadQueue  = new ArrayDeque<BluetoothGattDescriptor>(); 

    //mBluetoothGattMap = new HashMap<String, BluetoothGatt>(); 
    return true; 
} 

/** 
* Connects to the GATT server hosted on the Bluetooth LE device. 
* 
* @param address The device address of the device. 
* 
* @return Return true if the connection is initiated successfully. The connection result 
*   is reported asynchronously through the 
*   {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} 
*   callback. 
*/ 
public boolean connect(final String address) { 
    if (mBluetoothAdapter == null || address == null) { 
     Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); 
     return false; 
    } 



    if(mBluetoothGattMap.containsKey(address)) { 
     Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); 
     if (mBluetoothGattMap.get(address).connect()) { 
      mConnectionState = STATE_CONNECTING; 
      return true; 
     } else { 
      return false; 
     } 
    } 

    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); 
    if (device == null) { 
     Log.w(TAG, "Device not found. Unable to connect."); 
     return false; 
    } 

    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    mBluetoothGattMap.put(address, device.connectGatt(this, false, mGattCallback)); 


    Log.d(TAG, "Trying to create a new connection to address " + address); 
    //mBluetoothDeviceAddress = address; 
    mConnectionState = STATE_CONNECTING; 
    return true; 
} 

/** 
* Disconnects an existing connection or cancel a pending connection. The disconnection result 
* is reported asynchronously through the 
* {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} 
* callback. 
*/ 
public void disconnect(String address) { 
    if (mBluetoothAdapter == null || !mBluetoothGattMap.containsKey(address)) { 
     Log.w(TAG, "BluetoothAdapter not initialized"); 
     return; 
    } 
    Log.i(TAG, "Disconnecting from gatt"); 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    mBluetoothGattMap.get(address).disconnect(); 
} 


public void close(String address) { 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    mBluetoothGattMap.get(address).close(); 
    mBluetoothGattMap.remove(address); 
    Log.w(TAG, "Succeeed removing it"); 
} 

public int getConnectionState(String address) { 
    Log.i(TAG, "getting connection state for " + address); 
    BluetoothGatt gatt = mBluetoothGattMap.get(address); 
    return mBluetoothManager.getConnectionState(gatt.getDevice(), BluetoothProfile.GATT); 
} 

/** 
* Request a read on a given {@code BluetoothGattCharacteristic}. The read result is reported 
* asynchronously through the {@code BluetoothGattCallback#onCharacteristicRead(android.bluetooth.BluetoothGatt, android.bluetooth.BluetoothGattCharacteristic, int)} 
* callback. 
* 
* @param characteristic The characteristic to read from. 
*/ 
public void readCharacteristic(String address, BluetoothGattCharacteristic characteristic) { 
    Log.i(TAG, "reading characteristic"); 
    if (mBluetoothAdapter == null || !mBluetoothGattMap.containsKey(address)) { 
     Log.w(TAG, "BluetoothAdapter not initialized"); 
     return; 
    } 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    if(mReadyToRead && mReady) { 
     boolean result = mBluetoothGattMap.get(address).readCharacteristic(characteristic); 
     mReadyToRead = false; 
     mReady = false; 
     if(!result) { 
      Log.i(TAG, "read failed"); 
     } 
    }else { 
     mCharacteristicReadQueue.push(characteristic); 
    } 
} 

public void writeCharacteristic(String address, BluetoothGattCharacteristic characteristic) { 
    Log.i(TAG, "writeCharacteristic - readyToWrite = " + mReadyToWrite + " queue size = " + mCharacteristicWriteQueue.size()); 
    if (mBluetoothAdapter == null || !mBluetoothGattMap.containsKey(address)) { 
     Log.w(TAG, "BluetoothAdapter not initialized"); 
     return; 
    } 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    if(mReadyToWrite && mReady) { 
     boolean result = mBluetoothGattMap.get(address).writeCharacteristic(characteristic); 
     mReadyToWrite = false; 
     mReady = false; 
     if(!result) { 
      Log.i(TAG, "characteristic write failed"); 
     } 
    }else { 
     mCharacteristicWriteQueue.push(characteristic); 
    } 
} 

public void readDescriptor(String address, BluetoothGattDescriptor descriptor) { 
    Log.i(TAG, "reading descriptor"); 
    if (mBluetoothAdapter == null || !mBluetoothGattMap.containsKey(address)) { 
     Log.w(TAG, "BluetoothAdapter not initialized"); 
     return; 
    } 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    if(mReadyToRead && mReady) { 
     boolean result = mBluetoothGattMap.get(address).readDescriptor(descriptor); 
     mReadyToRead = false; 
     mReady = false; 
     if(!result) { 
      Log.i(TAG, "descriptor read failed"); 
     } 
    }else { 
     mDescriptorReadQueue.push(descriptor); 
    } 
} 

public void writeDescriptor(String address, BluetoothGattDescriptor descriptor) { 
    Log.i(TAG, "writing descriptor for characteristic " + descriptor.getCharacteristic().getUuid().toString()); 
    if (mBluetoothAdapter == null || !mBluetoothGattMap.containsKey(address)) { 
     Log.w(TAG, "BluetoothAdapter not initialized"); 
     return; 
    } 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    if(mReadyToWrite && mReady) { 
     boolean result = mBluetoothGattMap.get(address).writeDescriptor(descriptor); 
     mReadyToWrite = false; 
     mReady = false; 
     if(!result) { 
      Log.i(TAG, "descriptor write failed"); 
     } 
    }else { 
     mDescriptorWriteQueue.push(descriptor); 
    } 
} 

public BluetoothGattCharacteristic getCharacteristic(String address, UUID uuid) { 
    if(!mBluetoothGattMap.containsKey(address)) { 
     Log.i(TAG, "Device address " + address + " not found"); 
     return null; 
    } 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    for(BluetoothGattService service : mBluetoothGattMap.get(address).getServices()) { 
     Log.i(TAG, "Service: " + service.getUuid().toString()); 
     for (BluetoothGattCharacteristic characteristic : service.getCharacteristics()) { 
      Log.i(TAG, "Characteristic: " + characteristic.getUuid().toString()); 
      if(characteristic.getUuid().equals(uuid)) { 
       return characteristic; 
      } 
     } 
    } 
    Log.i(TAG, "Characteristic not found"); 
    return null; 
} 

public Set<String> getConnectedDevices(){ 
    return this.mBluetoothGattMap.keySet(); 
} 

/** 
* Enables or disables notification on a give characteristic. 
* 
* @param characteristic Characteristic to act on. 
* @param enabled If true, enable notification. False otherwise. 
*/ 
public void setCharacteristicNotification(String address, BluetoothGattCharacteristic characteristic, boolean enabled) { 
    if (mBluetoothAdapter == null || !mBluetoothGattMap.containsKey(address)) { 
     Log.w(TAG, "BluetoothAdapter not initialized"); 
     return; 
    } 
    try { 
     synchronized (Thread.currentThread()) { 
      Thread.currentThread().wait(100); 
     } 
    }catch(InterruptedException e){ 
     //ignore 
    } 
    mBluetoothGattMap.get(address).setCharacteristicNotification(characteristic, enabled); 
    BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID.fromString(GattAttributes.CLIENT_CHAR_CONFIG)); 
    if(descriptor != null) { 
     boolean status = descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
     Log.i(TAG, "descriptor " + descriptor.getUuid().toString() + " setValue() status: " + status); 
     Log.i(TAG, "descriptor value: " + descriptor.getValue()); 
     writeDescriptor(address, descriptor); 
    } 
} 

public void setPhoneEvents(byte priorities) { 
    for(String address : mBluetoothGattMap.keySet()) { 
     BluetoothGattCharacteristic characteristic = getCharacteristic(address, UUID.fromString(GattAttributes.ALERT_ATTRIBUTE)); 
     if (characteristic != null) { 
      byte prioritiesBuf[] = new byte[1]; 
      prioritiesBuf[0] = priorities; 
      characteristic.setValue(prioritiesBuf); 
      writeCharacteristic(address, characteristic); 
      Log.i(TAG, String.format("Forwarded phone alert priorities: 0x%X", priorities)); 
     } else { 
      Log.e(TAG, "Failed to get the Alert ID characteristic from Gatt Server for device address " + address); 
     } 
    } 
} 

/** 
* Retrieves a list of supported GATT services on the connected device. This should be 
* invoked only after {@code BluetoothGatt#discoverServices()} completes successfully. 
* 
* @return A {@code List} of supported services. 
*/ 
public List<BluetoothGattService> getSupportedGattServices(String address) { 
    if (mBluetoothGattMap.get(address) == null) return null; 

    return mBluetoothGattMap.get(address).getServices(); 
} 
+0

你有没有解决这个问题?我有类似的问题...我断开'BluetoothGatt',然后当呼叫表明断开,我关闭'BluetoothGatt',但它似乎连接实际上并没有断开/关闭。一旦关闭我的应用程序,连接关闭,外围设备返回广告,所以我知道外设的行为是正确的。 – mtrewartha

这种情况持续发生的问题是它会在用户定义的 名和断开的BLE装置停止广播,我可以 再也找不到它,当我扫描或如果我尝试之后我连接到它后 读取用户定义的名称并断开连接。

不应该是您的BLE设备在连接断开后不久需要启动广告吗? 我也建议你可以让你的BLE设备宣传你的定制服务,而不是你的应用程序连接然后阅读特性;你只需使用“ScanFilter”来过滤你最喜欢的设备。 你只是让低级代码做到这一点。

+0

断开连接后的某些设备不会广播。我必须重新启动它们才能将它们带回 –

+0

了解。对于这种情况,即使你拖延时间,设备应该仍然没有播出权?为什么不使用相同的行为设备。 –

观察到的行为实际上是BLE外围设备的一项功能,而不是Android,或者更一般的*设备程序。

我最近一直在使用Laird BL600--它有一个'Over the Air',OTA,编程模式 - 并且当启用该模式时,该模块在被供电后广告OTA服务长达10秒在:就是这样。在这种情况下,外设应用程序已被设定为在任何连接断开后不会退出广告。要重新进入OTA模式,需要设备的重新启动。根据Guo的建议,如果能够控制外设程序,BLE外设就可以在其广告数据包中包含一个可读标识符(设备名称)和主服务的GUID--这将使过滤哪些设备更容易呈现给用户。

当用户希望连接到外围设备时,如果设备仍在广告范围内,那么只有使用device.connectGatt(this, false, mGattCallback) 才能成功。我认为这个调用中的第二个参数 - 'autoconnect'的意图是在Android中将连接标记为待定 - 并且在设备返回到范围和广告时连接应该自动发生 - 但是我没有发现这是非常可靠的。