RxBleConnection.setupNotification 仅适用于两个特征中的第一个
RxBleConnection.setupNotification work for only the first of two characteristics
我很难找出使用 RxAndroidBle 的意外行为。
问题的简短形式是我需要从特定设备的两个特征接收顺序通知。在下面的示例中,我扫描了 SERVICE_UUID,并(按顺序)设置了 CHARACTERISTIC_FOO_UUID 和 CHARACTERISTIC_BAR_UUID 的通知。我需要根据两个特征的响应做一些事情——在我的示例中,我只是将 byte[] 存储在成员变量中。
我遇到的问题是第一个特征会返回,但第二个不会。如果我翻转顺序,它仍然是链中第一个特征。下面,我展示了调试输出,它表明通知调用对两者都发生了,包括低级描述符写入,但由于某种原因,第二个没有返回报告。 (假设我订阅了 Observable。)
我已经能够在没有 RxAndroidBle 的情况下让它工作。我也有一个使用 RxAndroidBle 的版本,它可以工作,但使用 ConnectionSharingAdapter 和几个订阅以不同的方式设置。下面的示例是对更简洁方法的尝试,但正如我所说,它似乎不起作用。
rxBleClient.scanBleDevices(SERVICE_UUID)
.first()
.flatMap(rxBleScanResult -> {
return Observable.just(rxBleScanResult.getBleDevice());
})
.flatMap(rxBleDevice -> {
return rxBleDevice.establishConnection(context, IS_AUTO_CONNECT);
})
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_FOO_UUID)
.flatMap(observable -> observable)
.flatMap(new Func1<byte[], Observable<RxBleConnection>>() {
@Override
public Observable<RxBleConnection> call(final byte[] notificationBytes) {
mFooBytes = notificationBytes;
return Observable.just(rxBleConnection);
}
})
)
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_BAR_UUID)
.flatMap(observable -> observable)
.flatMap(new Func1<byte[], Observable<RxBleConnection>>() {
@Override
public Observable<RxBleConnection> call(final byte[] notificationBytes) {
mBarBytes = notificationBytes;
return Observable.just(rxBleConnection);
}
})
)
这是 RxBle 调试输出——我在输出中用 "CHARACTERISTIC_FOO_UUID" 编辑了实际的 uuid。
12-22 12:13:43.322 12074-12074/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationScan(217963087)
12-22 12:13:43.322 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationScan(217963087)
12-22 12:13:43.412 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationScan(217963087)
12-22 12:13:43.682 12074-12074/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationConnect(37012551)
12-22 12:13:43.682 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationConnect(37012551)
12-22 12:13:44.052 12074-12085/com.foo.example D/RxBle#BluetoothGatt: onConnectionStateChange newState=2 status=0
12-22 12:13:44.092 12074-12558/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationServicesDiscover(72789039)
12-22 12:13:44.092 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationConnect(37012551)
12-22 12:13:44.092 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationServicesDiscover(72789039)
12-22 12:13:45.232 12074-12086/com.foo.example D/RxBle#BluetoothGatt: onServicesDiscovered status=0
12-22 12:13:45.262 12074-12558/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationDescriptorWrite(8700606)
12-22 12:13:45.262 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationServicesDiscover(72789039)
12-22 12:13:45.262 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationDescriptorWrite(8700606)
12-22 12:13:45.342 12074-12085/com.foo.example D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
12-22 12:13:45.362 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(8700606)
12-22 12:13:46.172 12074-12086/com.foo.example D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=CHARACTERISTIC_FOO_UUID
12-22 12:13:46.192 12074-12558/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationDescriptorWrite(179103302)
12-22 12:13:46.192 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationDescriptorWrite(179103302)
12-22 12:13:46.272 12074-12201/com.foo.example D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
12-22 12:13:46.272 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(179103302)
下面是一个使用 RxAndroidBle 的版本的简化示例,它确实可以工作,但具有多个订阅和一个 ConnectionSharingAdapter。在这两个版本中,Observable 都会在其他地方订阅,所以我试图避免对多个订阅的所有簿记——这里的 CompositeSubscription 和其他地方的其他订阅。上面的方法有问题,但似乎更实用。在我的实际应用中,我做的事情更复杂,所以上面的版本实际上变得更容易理解,在这个简化版本中它可能看起来有点多代码。
CompositeSubscription bleConnectionSubscriptions = new CompositeSubscription();
Observable<RxBleConnection> bleConnectionObservable =
bleConnectionObservable = bleDevice.establishConnection(context, IS_AUTO_CONNECT)
.compose(new ConnectionSharingAdapter());
Subscription subscription =
bleConnectionObservable
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_FOO_INGREDIENTS))
.flatMap(observable -> observable)
.subscribe(notificationBytes -> mFooBytes = notificationBytes);
bleConnectionSubscriptions.add(subscription);
subscription =
bleConnectionObservable
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_BAR_INGREDIENTS))
.flatMap(observable -> observable)
.subscribe(notificationBytes -> mBarBytes = notificationBytes);
bleConnectionSubscriptions.add(subscription);
正如您在日志中看到的那样,两个通知都已正确设置,但第二个通知未收到任何值。怀疑是在设置通知之前发出了 BAR 值。
您可以在连接开始时使用如下代码设置这两个通知:
rxBleClient.scanBleDevices(SERVICE_UUID)
.first() // subscribe to the first device that is available...
.flatMap(rxBleScanResult -> rxBleScanResult.getBleDevice().establishConnection(context, IS_AUTO_CONNECT)) // ...establish the connection...
.flatMap(rxBleConnection -> Observable.combineLatest( // ...when connection is established we combine latest results from...
rxBleConnection.setupNotification(CHARACTERISTIC_FOO_INGREDIENTS) // ...setup notification on FOO...
.flatMap(observable -> observable) // ...flatMap it to values...
.first(), // ...take the first value so the notification will be disposed...
rxBleConnection.setupNotification(CHARACTERISTIC_BAR_INGREDIENTS) // ...setup notification on BAR...
.flatMap(observable -> observable) // ...flatMap it to values...
.first(), // ...take the first value so the notification will be disposed...
((fooBytes, barBytes) -> {
mFooBytes = fooBytes;
mBarBytes = barBytes;
return true; // return whatever
})
))
.first(); // after the first returned value the connection will be disconnected
我很难找出使用 RxAndroidBle 的意外行为。
问题的简短形式是我需要从特定设备的两个特征接收顺序通知。在下面的示例中,我扫描了 SERVICE_UUID,并(按顺序)设置了 CHARACTERISTIC_FOO_UUID 和 CHARACTERISTIC_BAR_UUID 的通知。我需要根据两个特征的响应做一些事情——在我的示例中,我只是将 byte[] 存储在成员变量中。
我遇到的问题是第一个特征会返回,但第二个不会。如果我翻转顺序,它仍然是链中第一个特征。下面,我展示了调试输出,它表明通知调用对两者都发生了,包括低级描述符写入,但由于某种原因,第二个没有返回报告。 (假设我订阅了 Observable。)
我已经能够在没有 RxAndroidBle 的情况下让它工作。我也有一个使用 RxAndroidBle 的版本,它可以工作,但使用 ConnectionSharingAdapter 和几个订阅以不同的方式设置。下面的示例是对更简洁方法的尝试,但正如我所说,它似乎不起作用。
rxBleClient.scanBleDevices(SERVICE_UUID)
.first()
.flatMap(rxBleScanResult -> {
return Observable.just(rxBleScanResult.getBleDevice());
})
.flatMap(rxBleDevice -> {
return rxBleDevice.establishConnection(context, IS_AUTO_CONNECT);
})
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_FOO_UUID)
.flatMap(observable -> observable)
.flatMap(new Func1<byte[], Observable<RxBleConnection>>() {
@Override
public Observable<RxBleConnection> call(final byte[] notificationBytes) {
mFooBytes = notificationBytes;
return Observable.just(rxBleConnection);
}
})
)
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_BAR_UUID)
.flatMap(observable -> observable)
.flatMap(new Func1<byte[], Observable<RxBleConnection>>() {
@Override
public Observable<RxBleConnection> call(final byte[] notificationBytes) {
mBarBytes = notificationBytes;
return Observable.just(rxBleConnection);
}
})
)
这是 RxBle 调试输出——我在输出中用 "CHARACTERISTIC_FOO_UUID" 编辑了实际的 uuid。
12-22 12:13:43.322 12074-12074/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationScan(217963087)
12-22 12:13:43.322 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationScan(217963087)
12-22 12:13:43.412 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationScan(217963087)
12-22 12:13:43.682 12074-12074/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationConnect(37012551)
12-22 12:13:43.682 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationConnect(37012551)
12-22 12:13:44.052 12074-12085/com.foo.example D/RxBle#BluetoothGatt: onConnectionStateChange newState=2 status=0
12-22 12:13:44.092 12074-12558/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationServicesDiscover(72789039)
12-22 12:13:44.092 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationConnect(37012551)
12-22 12:13:44.092 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationServicesDiscover(72789039)
12-22 12:13:45.232 12074-12086/com.foo.example D/RxBle#BluetoothGatt: onServicesDiscovered status=0
12-22 12:13:45.262 12074-12558/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationDescriptorWrite(8700606)
12-22 12:13:45.262 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationServicesDiscover(72789039)
12-22 12:13:45.262 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationDescriptorWrite(8700606)
12-22 12:13:45.342 12074-12085/com.foo.example D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
12-22 12:13:45.362 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(8700606)
12-22 12:13:46.172 12074-12086/com.foo.example D/RxBle#BluetoothGatt: onCharacteristicChanged characteristic=CHARACTERISTIC_FOO_UUID
12-22 12:13:46.192 12074-12558/com.foo.example D/RxBle#Radio: QUEUED RxBleRadioOperationDescriptorWrite(179103302)
12-22 12:13:46.192 12074-12281/com.foo.example D/RxBle#Radio: STARTED RxBleRadioOperationDescriptorWrite(179103302)
12-22 12:13:46.272 12074-12201/com.foo.example D/RxBle#BluetoothGatt: onDescriptorWrite descriptor=00002902-0000-1000-8000-00805f9b34fb status=0
12-22 12:13:46.272 12074-12281/com.foo.example D/RxBle#Radio: FINISHED RxBleRadioOperationDescriptorWrite(179103302)
下面是一个使用 RxAndroidBle 的版本的简化示例,它确实可以工作,但具有多个订阅和一个 ConnectionSharingAdapter。在这两个版本中,Observable 都会在其他地方订阅,所以我试图避免对多个订阅的所有簿记——这里的 CompositeSubscription 和其他地方的其他订阅。上面的方法有问题,但似乎更实用。在我的实际应用中,我做的事情更复杂,所以上面的版本实际上变得更容易理解,在这个简化版本中它可能看起来有点多代码。
CompositeSubscription bleConnectionSubscriptions = new CompositeSubscription();
Observable<RxBleConnection> bleConnectionObservable =
bleConnectionObservable = bleDevice.establishConnection(context, IS_AUTO_CONNECT)
.compose(new ConnectionSharingAdapter());
Subscription subscription =
bleConnectionObservable
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_FOO_INGREDIENTS))
.flatMap(observable -> observable)
.subscribe(notificationBytes -> mFooBytes = notificationBytes);
bleConnectionSubscriptions.add(subscription);
subscription =
bleConnectionObservable
.flatMap(rxBleConnection ->
rxBleConnection.setupNotification(CHARACTERISTIC_BAR_INGREDIENTS))
.flatMap(observable -> observable)
.subscribe(notificationBytes -> mBarBytes = notificationBytes);
bleConnectionSubscriptions.add(subscription);
正如您在日志中看到的那样,两个通知都已正确设置,但第二个通知未收到任何值。怀疑是在设置通知之前发出了 BAR 值。
您可以在连接开始时使用如下代码设置这两个通知:
rxBleClient.scanBleDevices(SERVICE_UUID)
.first() // subscribe to the first device that is available...
.flatMap(rxBleScanResult -> rxBleScanResult.getBleDevice().establishConnection(context, IS_AUTO_CONNECT)) // ...establish the connection...
.flatMap(rxBleConnection -> Observable.combineLatest( // ...when connection is established we combine latest results from...
rxBleConnection.setupNotification(CHARACTERISTIC_FOO_INGREDIENTS) // ...setup notification on FOO...
.flatMap(observable -> observable) // ...flatMap it to values...
.first(), // ...take the first value so the notification will be disposed...
rxBleConnection.setupNotification(CHARACTERISTIC_BAR_INGREDIENTS) // ...setup notification on BAR...
.flatMap(observable -> observable) // ...flatMap it to values...
.first(), // ...take the first value so the notification will be disposed...
((fooBytes, barBytes) -> {
mFooBytes = fooBytes;
mBarBytes = barBytes;
return true; // return whatever
})
))
.first(); // after the first returned value the connection will be disconnected