我正在尝试修复现有的React Native库react-native-ble-plx,并在existing Java code中添加onBackPressureBuffer()。
我知道这很丑陋,但是我现在没有时间提交PR,并且有一个pending issue可以解决问题。 我这样做是因为事件发射器的工作频率为200Hz。我需要一种安全的方法来在本机端缓冲项目,同时在JavaScript端按自己的速度消费它们。
所以代码如下:
final Subscription subscription = Observable.defer(new Func0<Observable<Observable<byte[]>>>() {
@Override
public Observable<Observable<byte[]>> call() {
int properties = gattCharacteristic.getProperties();
BluetoothGattDescriptor cccDescriptor = gattCharacteristic
.getDescriptor(Characteristic.CLIENT_CHARACTERISTIC_CONFIG_UUID);
NotificationSetupMode setupMode = cccDescriptor != null ? NotificationSetupMode.QUICK_SETUP
: NotificationSetupMode.COMPAT;
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
return connection.setupNotification(gattCharacteristic, setupMode);
}
if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
return connection.setupIndication(gattCharacteristic, setupMode);
}
return Observable.error(new CannotMonitorCharacteristicException(gattCharacteristic));
}
}).onBackpressureBuffer(1000) <---- Here is my modification
.flatMap(new Func1<Observable<byte[]>, Observable<byte[]>>() {
@Override
public Observable<byte[]> call(Observable<byte[]> observable) {
return observable;
}
}).doOnUnsubscribe(new Action0() {
@Override
public void call() {
promise.resolve(null);
transactions.removeSubscription(transactionId);
}
}).subscribe(new Observer<byte[]>() {
@Override
public void onCompleted() {
promise.resolve(null);
transactions.removeSubscription(transactionId);
}
@Override
public void onError(Throwable e) {
errorConverter.toError(e).reject(promise);
transactions.removeSubscription(transactionId);
}
@Override
public void onNext(byte[] bytes) {
characteristic.logValue("Notification from", bytes);
WritableArray jsResult = Arguments.createArray();
jsResult.pushNull();
jsResult.pushMap(characteristic.toJSObject(bytes));
jsResult.pushString(transactionId);
sendEvent(Event.ReadEvent, jsResult);
}
});
我的问题是,即使添加了这些东西,我仍然遇到MissingBackPressure异常。
我尝试过onBackPressureDrop(),但行为却完全相同。因此,我认为我做错了,但是现在不知道为什么。
任何帮助表示赞赏。
答案 0 :(得分:0)
正如您所说的,您在使用react-native
库时遇到了问题,上面的代码以前确实抛出过MissingBackpressureException
。
从.onBackpressureDrop()
的Javadoc中摘录:
指示一个Observable发出的项目快于其观察者消耗它们丢弃的速度, 而不是发出观察者不准备观察的那些项目。
如果下游请求计数为0,则Observable将避免调用{@code onNext},直到 观察者再次调用{@code request(n)}来增加请求数。
- 背压:
- 操作员尊重下游的背压,并以无限制的方式消耗{@code Observable}源 方式(即不对其施加反压)。
- 计划程序:
- {@ code onBackpressureDrop}在特定的{@link Scheduler}上默认不运行。
您会看到链中的下一个运算符是.flatMap()
,.doOnUnsubscribe()
和.subscribe()
。
来自.flatMap()
的Javadoc关于反压:
背压: 操作员尊重下游的背压。外部{@code Observable}被消耗了 在无限制模式下(即未对其施加反压)。内部{@code Observable}有望兑现 背压;如果违反,则操作员可能发出{@code MissingBackpressureException}信号。
Javadoc .doOnUnsubscribe()
:
背压: {@ code doOnUnsubscribe}不会与反压力请求或值传递交互;背压 行为保留在上游和下游之间。
还有.subscribe()
:
背压: 操作员以无限制的方式使用了{@code Observable}源(即,否 施加反压)。
如您所见,.onBackpressure*()
下面的运算符都没有对其施加反压。您需要添加一个在.onBackpressure*()
之后执行此操作的运算符。 .observeOn(Scheduler)
Javadoc .observeOn()
:
背压: 该操作员尊重来自下游的背压,并期望来自源{@code Observable}的背压。违反此 期望将导致{@code MissingBackpressureException}。这是最常见的运算子, 弹出;在供应链中寻找不支持背压的资源, 例如{@code interval},{@ code timer},{code PublishSubject}或{@code BehaviorSubject},然后应用任何 {strong>之前操作者中的{@code onBackpressureXXX}操作者应用{@code watchOn}本身。
因此可行的代码如下:
final Subscription subscription = Observable.defer(new Func0<Observable<Observable<byte[]>>>() {
@Override
public Observable<Observable<byte[]>> call() {
int properties = gattCharacteristic.getProperties();
BluetoothGattDescriptor cccDescriptor = gattCharacteristic
.getDescriptor(Characteristic.CLIENT_CHARACTERISTIC_CONFIG_UUID);
NotificationSetupMode setupMode = cccDescriptor != null ? NotificationSetupMode.QUICK_SETUP
: NotificationSetupMode.COMPAT;
if ((properties & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
return connection.setupNotification(gattCharacteristic, setupMode);
}
if ((properties & BluetoothGattCharacteristic.PROPERTY_INDICATE) != 0) {
return connection.setupIndication(gattCharacteristic, setupMode);
}
return Observable.error(new CannotMonitorCharacteristicException(gattCharacteristic));
}
})
.flatMap(new Func1<Observable<byte[]>, Observable<byte[]>>() {
@Override
public Observable<byte[]> call(Observable<byte[]> observable) {
return observable;
}
})
.doOnUnsubscribe(new Action0() {
@Override
public void call() {
promise.resolve(null);
transactions.removeSubscription(transactionId);
}
})
.onBackpressureBuffer(1000) // <---- Here is my modification
.observeOn(Schedulers.trampoline()) // <---- an operator that does backpressure the above
.subscribe(new Observer<byte[]>() {
@Override
public void onCompleted() {
promise.resolve(null);
transactions.removeSubscription(transactionId);
}
@Override
public void onError(Throwable e) {
errorConverter.toError(e).reject(promise);
transactions.removeSubscription(transactionId);
}
@Override
public void onNext(byte[] bytes) {
characteristic.logValue("Notification from", bytes);
WritableArray jsResult = Arguments.createArray();
jsResult.pushNull();
jsResult.pushMap(characteristic.toJSObject(bytes));
jsResult.pushString(transactionId);
sendEvent(Event.ReadEvent, jsResult);
}
});