Уведомление о настройке конечного автомата RxAndroidBle создает бесконечный цикл onDoNext
В настоящее время я пытаюсь изменить свой исходный код, чтобы использовать библиотеку RxAndroidBle.
Я реализовал конечный автомат, который при каждой успешной операции Bluetooth вызывает (уведомляет, пишет, читает и т. Д.) Следующее состояние. RxBleConnection всегда должен быть установлен, пока работает устройство Bluetooth.
Моя реализация для уведомления о настройке выглядит следующим образом:
protected void setNotificationOn(UUID characteristic) {
if (isConnected()) {
final Disposable disposable = connectionObservable
.flatMap(rxBleConnection -> rxBleConnection.setupNotification(characteristic))
.doOnNext(notificationObservable -> {
Timber.d("Successful set notification on for %s", BluetoothGattUuid.prettyPrint(characteristic));
nextMachineStateStep();
}
)
.flatMap(notificationObservable -> notificationObservable)
.observeOn(AndroidSchedulers.mainThread())
.retry(BT_RETRY_TIMES_ON_ERROR)
.subscribe(
bytes -> {
onBluetoothNotify(characteristic, bytes);
Timber.d("onCharacteristicChanged %s: %s",
BluetoothGattUuid.prettyPrint(characteristic),
byteInHex(bytes));
},
throwable -> onError(throwable)
);
compositeDisposable.add(disposable);
}
}
если я только один раз установил уведомление для характеристики, она работает, но если произошла ошибка или если я попытаюсь установить ее еще раз, я застряну в бесконечном цикле в doOnNext, и метод setNotificationOn никогда не завершается. Я думал, doOnNext вызывается только один раз при успешной настройке уведомлений!? (исключение BleConflictingNotificationAlreadySetException никогда не генерируется, как и другие исключения!?)
Как я могу повторно настроить уведомление на одну и ту же характеристику?
Есть ли лучший способ создать конечный автомат с RxAndroidBle/RxJava2? (Мне нужно вызвать различные операции Bluetooth)
Вы найдете мою полную реализацию здесь
Редактировать:
Однако, если кто-то попытается снова подписаться на.setupNotification() для той же характеристики, оба подписчика будут использовать одно и то же уведомление.
Спасибо за объяснение, так doOnNext()
больше не вызывается, потому что если я подпишусь на setupNotification()
опять уведомление об успешной настройке.
Можно ли проверить, настроено ли уже уведомление (чтобы я мог пропустить этот шаг, чтобы перейти к следующему состоянию машины)?
почему ваш API выглядит так или чего именно вы хотите достичь
Я хочу добиться, чтобы связь Bluetooth через RxAndroidBle была абстрактной, чтобы подкласс class BluetoothCommunication
можно просто использовать методы:
protected void writeBytes(UUID characteristic, byte[] bytes)
protected void readBytes(UUID characteristic)
protected void setIndicationOn(UUID characteristic)
protected void setNotificationOn(UUID characteristic)
/* Method is triggered if a Bluetooth data is read from a device. */
protected void onBluetoothRead(UUID characteristic, byte[] value) {}
/* Method is triggered if a Bluetooth data from a device is notified */
protected void onBluetoothNotify(UUID characteristic, byte[] value) {}
настроить последовательность связи Bluetooth. Связь / последовательность / алгоритм Bluetooth всегда отличаются и не могут быть параметризованы. Но это всегда последовательно. Чтобы инициализировать шкалу Bluetooth, во-первых, мне нужно настроить уведомления A, а затем B. Во-вторых, мне нужно отправить команду C, после чего я получу один или несколько уведомлений, после чего мне придется отправить команду B и так далее. Я поддерживаю множество весов Bluetooth от разных производителей, количество команд / уведомлений о настройке и алгоритм всегда разные.
Вы можете увидеть подклассы с их различным алгоритмом здесь
По моему опыту, RxJava2 не должен иметь дополнительный конечный автомат, так как это уже библиотека, которая обрабатывает состояние
Как я могу абстрагировать состояние дескриптора библиотеки для подклассов?
1 ответ
Я думал, doOnNext вызывается только один раз при успешной настройке уведомлений!?
В вашем случае это .doOnNext()
будет вызываться для каждой успешной настройки уведомления после установления соединения. Если соединение будет разорвано по какой-либо причине, .retry()
оператор перепишется на connectionObservable
который может начать новое соединение, которое вызовет новую настройку уведомлений.
Вывод: твой .doOnNext()
может быть вызван до BT_RETRY_TIMES_ON_ERROR
раз для каждого .subscribe()
Как я могу повторно настроить уведомление на одну и ту же характеристику?
Уведомление активно, пока .setupNotification()
подписан, и нет необходимости настраивать его снова. Однако, если кто-то попытается снова подписаться на .setupNotification()
по одной и той же характеристике оба подписчика будут делить одно и то же уведомление. В вашем примере уведомление будет активным до compositeDisposable
будет уничтожен или соединение будет разорвано (в этом случае новое соединение будет установлено до BT_RETRY_TIMES_ON_ERROR
время для каждой подписки, как указано выше).
Есть ли лучший способ создать конечный автомат с RxAndroidBle/RxJava2? (Мне нужно вызвать различные операции Bluetooth)
RxJava2 позволяет создавать преобразования состояний и планировать подписку на определенные Observable
разными способами (также последовательными), например
Disposable disposable = Observable.concat(Arrays.asList(
Observable.just("start").doOnSubscribe(disposable1 -> Log.d("Subscribe", "start")),
Observable.just("0").delay(3, TimeUnit.SECONDS).doOnSubscribe(disposable1 -> Log.d("Subscribe", "0")),
Observable.just("1").delay(2, TimeUnit.SECONDS).doOnSubscribe(disposable1 -> Log.d("Subscribe", "1")),
Observable.just("2").delay(1, TimeUnit.SECONDS).doOnSubscribe(disposable1 -> Log.d("Subscribe", "2")),
Observable.just("end").doOnSubscribe(disposable1 -> Log.d("Subscribe", "end"))
))
.subscribe(s -> Log.d("Result", s));
// 2019-01-04 12:45:13.364 31887-31887/ D/Subscribe: start
// 2019-01-04 12:45:13.364 31887-31887/ D/Result: start
// 2019-01-04 12:45:13.364 31887-31887/ D/Subscribe: 0
// 2019-01-04 12:45:16.366 31887-32529/ D/Result: 0
// 2019-01-04 12:45:16.367 31887-32529/ D/Subscribe: 1
// 2019-01-04 12:45:18.367 31887-32535/ D/Result: 1
// 2019-01-04 12:45:18.368 31887-32535/ D/Subscribe: 2
// 2019-01-04 12:45:19.369 31887-32537/ D/Result: 2
// 2019-01-04 12:45:19.371 31887-32537/ D/Subscribe: end
// 2019-01-04 12:45:19.372 31887-32537/ D/Result: end
Есть и другие операторы, которые делают процессы также последовательными.
Более подходящий вопрос - почему ваш API выглядит так или чего именно вы хотите достичь, например,
- Соответствует ли он указанному внешнему API?
- Контролируется ли процесс внешним лицом?
- Можно ли это упростить на внешнем уровне API (т. Е. Один метод, такой как
.getMeasurementData(device, callbackForResult)
)? - Является ли процесс связи по Bluetooth параметризуемым или алгоритм всегда один и тот же?
По моему опыту, RxJava2 не нуждается в дополнительном автомате состояний, поскольку это уже библиотека, которая обрабатывает состояние. Как только требования известны, можно смоделировать цепочку операторов RxJava2 так, чтобы она выполняла именно то, что нужно.
Можно ли проверить, настроено ли уже уведомление (чтобы я мог пропустить этот шаг, чтобы перейти к следующему состоянию машины)?
Нет, проверить это невозможно, однако вызывающий абонент знает, был ли он уже установлен.