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();
}
这种情况持续发生的问题是它会在用户定义的 名和断开的BLE装置停止广播,我可以 再也找不到它,当我扫描或如果我尝试之后我连接到它后 读取用户定义的名称并断开连接。
不应该是您的BLE设备在连接断开后不久需要启动广告吗? 我也建议你可以让你的BLE设备宣传你的定制服务,而不是你的应用程序连接然后阅读特性;你只需使用“ScanFilter”来过滤你最喜欢的设备。 你只是让低级代码做到这一点。
断开连接后的某些设备不会广播。我必须重新启动它们才能将它们带回 –
了解。对于这种情况,即使你拖延时间,设备应该仍然没有播出权?为什么不使用相同的行为设备。 –
观察到的行为实际上是BLE外围设备的一项功能,而不是Android,或者更一般的*设备程序。
我最近一直在使用Laird BL600--它有一个'Over the Air',OTA,编程模式 - 并且当启用该模式时,该模块在被供电后广告OTA服务长达10秒在:就是这样。在这种情况下,外设应用程序已被设定为在任何连接断开后不会退出广告。要重新进入OTA模式,需要设备的重新启动。根据Guo的建议,如果能够控制外设程序,BLE外设就可以在其广告数据包中包含一个可读标识符(设备名称)和主服务的GUID--这将使过滤哪些设备更容易呈现给用户。
当用户希望连接到外围设备时,如果设备仍在广告范围内,那么只有使用device.connectGatt(this, false, mGattCallback)
才能成功。我认为这个调用中的第二个参数 - 'autoconnect'的意图是在Android中将连接标记为待定 - 并且在设备返回到范围和广告时连接应该自动发生 - 但是我没有发现这是非常可靠的。
你有没有解决这个问题?我有类似的问题...我断开'BluetoothGatt',然后当呼叫表明断开,我关闭'BluetoothGatt',但它似乎连接实际上并没有断开/关闭。一旦关闭我的应用程序,连接关闭,外围设备返回广告,所以我知道外设的行为是正确的。 – mtrewartha