RxAndroidBle - 如何断开所有连接的设备?
RxAndroidBle - How to disconnect all connected devices?
我正在使用很棒的 rxandroidble 库进行 BLE 控制。
我保持活动之间的联系。
在开始扫描之前,我想先断开所有连接的设备。
如果有很多连接,有时它不起作用。
这是我正在使用的解决方案:
public void doScan() {
if (isScanning()) return;
// disconnect all connected devices first:
while(BleController.getDefault().getDisconnectTriggerSubject().hasObservers()){
BleController.getDefault().getDisconnectTriggerSubject().onNext(null);
}
scanSubscription = rxBleClient.scanBleDevices(
new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build(),
new ScanFilter.Builder()
// add custom filters if needed
.build()
)
.filter(rxBleScanResult -> !TextUtils.isEmpty(rxBleScanResult.getBleDevice().getName()))
.observeOn(AndroidSchedulers.mainThread())
.doOnUnsubscribe(this::clearSubscription)
.subscribe(resultsAdapter::addScanResult, this::onScanFailure);
updateButtonUIState();
}
BleController
使用主应用程序的上下文进行初始化,并保留 connectionObservable
、disconnectTriggerSubject
、rxBleClient
.
有什么更好的解决方案?
如有任何帮助,我们将不胜感激!
从您的 post 我可以看出您将 BLE scanning/connection 逻辑与 UI/Activity 逻辑混合在一起。这可能是正确管理连接的问题。
你可以做的是将所有 BLE 逻辑放入你的 BleController
中,它已经有了一个好名字,但在你的情况下似乎是一个 BleObjectsContainer
.
例如,您只能从 BleController
公开以 Activities
不需要处理的方式满足您的特定用例的可观察对象。即您的 BleController
可以处理扫描:
private final BehaviorRelay<Boolean> isScanningPublishRelay = BehaviorRelay.create(false); // a relay (that cannot emit an error) that emits when a scan is ongoing
private Observable<ScanResult> scanDevicesWithNonNullNameObs = rxBleClient.scanBleDevices(new ScanSettings.Builder().build())
.filter(scanResult -> !TextUtils.isEmpty(scanResult.getBleDevice().getName()))
.doOnSubscribe(() -> isScanningPublishRelay.call(true)) // when scan is subscribed/started emit true
.doOnUnsubscribe(() -> isScanningPublishRelay.call(false)) // when scan is stopped emit false
.subscribeOn(AndroidSchedulers.mainThread()) // the above emissions will happen on the same thread. should be serialized
.unsubscribeOn(AndroidSchedulers.mainThread()) // the above emissions will happen on the same thread. should be serialized
.share(); // share this observable so no matter how many places in the code will subscribe the scan is started once and `isScanningPublishRelay` is called once
public Observable<ScanResult> scanDevicesWithNonNullName() { // getter for the scan observable
return scanDevicesWithNonNullNameObs;
}
除了扫描之外,它还会为每个需要它的 Activity
处理您的特定用例:
class ScanInProgress extends Throwable {
// ...
}
public Observable<YourActivityUseCaseModel> doYourSpecificStuff(Observable<RxBleConnection> connectionObservable) {
return Observable.merge(
connectionObservable,
isScanningPublishRelay
.takeFirst(aBoolean -> aBoolean)
.flatMap(ignored -> Observable.error(new ScanInProgress())) // this will only emit an error when a scan is ongoing
)
.flatMap(...); // do the rest of your stuff
}
通过这种方式,在您的活动中,您只需订阅他们需要的任何模型,并在一个专门用于它的地方处理 BLE (BleController
)。
在上面的示例中,您需要提供 Observable<RxBleConnection>
,但它可以通过许多不同的方式实现,并且也可以在 BleController
中进行管理,因此它不会在界面中公开。
我正在使用很棒的 rxandroidble 库进行 BLE 控制。
我保持活动之间的联系。
在开始扫描之前,我想先断开所有连接的设备。
如果有很多连接,有时它不起作用。
这是我正在使用的解决方案:
public void doScan() {
if (isScanning()) return;
// disconnect all connected devices first:
while(BleController.getDefault().getDisconnectTriggerSubject().hasObservers()){
BleController.getDefault().getDisconnectTriggerSubject().onNext(null);
}
scanSubscription = rxBleClient.scanBleDevices(
new ScanSettings.Builder()
.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
.setCallbackType(ScanSettings.CALLBACK_TYPE_ALL_MATCHES)
.build(),
new ScanFilter.Builder()
// add custom filters if needed
.build()
)
.filter(rxBleScanResult -> !TextUtils.isEmpty(rxBleScanResult.getBleDevice().getName()))
.observeOn(AndroidSchedulers.mainThread())
.doOnUnsubscribe(this::clearSubscription)
.subscribe(resultsAdapter::addScanResult, this::onScanFailure);
updateButtonUIState();
}
BleController
使用主应用程序的上下文进行初始化,并保留 connectionObservable
、disconnectTriggerSubject
、rxBleClient
.
有什么更好的解决方案? 如有任何帮助,我们将不胜感激!
从您的 post 我可以看出您将 BLE scanning/connection 逻辑与 UI/Activity 逻辑混合在一起。这可能是正确管理连接的问题。
你可以做的是将所有 BLE 逻辑放入你的 BleController
中,它已经有了一个好名字,但在你的情况下似乎是一个 BleObjectsContainer
.
例如,您只能从 BleController
公开以 Activities
不需要处理的方式满足您的特定用例的可观察对象。即您的 BleController
可以处理扫描:
private final BehaviorRelay<Boolean> isScanningPublishRelay = BehaviorRelay.create(false); // a relay (that cannot emit an error) that emits when a scan is ongoing
private Observable<ScanResult> scanDevicesWithNonNullNameObs = rxBleClient.scanBleDevices(new ScanSettings.Builder().build())
.filter(scanResult -> !TextUtils.isEmpty(scanResult.getBleDevice().getName()))
.doOnSubscribe(() -> isScanningPublishRelay.call(true)) // when scan is subscribed/started emit true
.doOnUnsubscribe(() -> isScanningPublishRelay.call(false)) // when scan is stopped emit false
.subscribeOn(AndroidSchedulers.mainThread()) // the above emissions will happen on the same thread. should be serialized
.unsubscribeOn(AndroidSchedulers.mainThread()) // the above emissions will happen on the same thread. should be serialized
.share(); // share this observable so no matter how many places in the code will subscribe the scan is started once and `isScanningPublishRelay` is called once
public Observable<ScanResult> scanDevicesWithNonNullName() { // getter for the scan observable
return scanDevicesWithNonNullNameObs;
}
除了扫描之外,它还会为每个需要它的 Activity
处理您的特定用例:
class ScanInProgress extends Throwable {
// ...
}
public Observable<YourActivityUseCaseModel> doYourSpecificStuff(Observable<RxBleConnection> connectionObservable) {
return Observable.merge(
connectionObservable,
isScanningPublishRelay
.takeFirst(aBoolean -> aBoolean)
.flatMap(ignored -> Observable.error(new ScanInProgress())) // this will only emit an error when a scan is ongoing
)
.flatMap(...); // do the rest of your stuff
}
通过这种方式,在您的活动中,您只需订阅他们需要的任何模型,并在一个专门用于它的地方处理 BLE (BleController
)。
在上面的示例中,您需要提供 Observable<RxBleConnection>
,但它可以通过许多不同的方式实现,并且也可以在 BleController
中进行管理,因此它不会在界面中公开。