Использование нескольких операторов .subscribe() с RxJava

Мое приложение для Android для периферийного устройства BLE записывает 2 разных характеристики устройства и получает уведомления от 2 других. Разработчики библиотеки RxAndroidBle предостерегают от нескольких подписок на один и тот же экземпляр RxBleConnection, но я не вижу никакого реалистичного способа объединить все эти операции ввода-вывода в один .subscribe(), тем более что одно из уведомлений — довольно постоянные данные " пожарный шланг".

Не зная ничего лучшего, я просто сохранял RxBleConnection в переменной и использовал ее в нескольких .subscribe(). Насколько я могу судить, это работает нормально. Я изучил ConnectionSharingAdapter библиотеки RxAndroidBle, но, хотя я проанализировал код, я не понимаю, какие преимущества он предлагает по сравнению с моим упрощенным подходом (хотя мне бы хотелось знать).

В общем, некоторые уточнения о том, как множественные .subscribe() вводят состояние, и потенциальные ловушки, были бы полезны. Вопросы:

  1. Что не так с сохранением RxBleConnection в переменной и использованием ее для нескольких .subscribe()?
  2. Если это проблема, как ConnectionSharingAdapter решает ее?
  3. Что значит сказать, что множественные подписки «вводят состояние» и как это может вызвать проблемы?
  4. Есть ли какой-нибудь чистый способ объединить все четыре характерные операции ввода-вывода в одну .subscribe() (которая не ухудшит производительность)?

person Robert Lewis    schedule 19.06.2017    source источник
comment
Этот вопрос слишком широк — может быть, было бы проще спросить разработчиков библиотеки, почему они не рекомендуют несколько подписок. С точки зрения чистого Rx, множественные подписки на один и тот же (холодный) поток действительно возможны только с субъектом (например, publish() RxJava), и обсуждение использования субъектов — это более широкий вопрос, на который, вероятно, уже есть ответы на этот вопрос. сайт и многие другие ресурсы.   -  person Whymarrh    schedule 19.06.2017
comment
Я задал им этот вопрос, и они сказали мне перенести обсуждение в StackOverflow, так что я здесь.   -  person Robert Lewis    schedule 19.06.2017
comment
Сам вопрос следует перефразировать так, чтобы он относился к библиотеке RxAndroidBle. У меня тот же вопрос о библиотеке, и я попал сюда из обсуждения библиотеки на github. @РобертЛьюис   -  person JohnnyLambada    schedule 03.01.2019


Ответы (1)


Что не так с сохранением RxBleConnection в переменной и использованием ее для нескольких .subscribe()? (...) Что значит сказать, что несколько подписок «вводят состояние» и как это может вызвать проблемы?

Эти два вопроса почти одинаковы. RxBleConnection — это абстракция над состоянием, в котором клиент BLE обменивается некоторыми пакетами рукопожатия с сервером BLE, после чего и клиент, и сервер считаются подключенными. К сожалению, по разным причинам это соединение может быть разорвано почти в любой момент (и это случается довольно часто), что не может быть легко выражено одной хранимой переменной RxBleConnection реактивным способом.

С другой стороны, наблюдение за RxBleDevice.establishConnection() приведет к распространению ошибки подписчику после разрыва соединения. Хотя ни одна из функций, которые выдает RxBleConnection, не будет работать после разрыва соединения - сохраненная переменная соединения не будет информировать о проблеме, когда она произойдет.

Поэтому, если пользователь сохраняет RxBleConnection в переменную, это вводит состояние, в котором может находиться переменная, и пользователь несет ответственность за распространение (очистку переменной) ошибок, которые могут произойти позже. Наоборот, подписка на .establishConnection() вызовет исключение, когда соединение не может быть использовано.

Как многие программисты могли заметить в ходе своей практики, управление состоянием является наиболее распространенным источником ошибок в приложениях. Уменьшение состояния — это способ снизить риск ошибок.

Есть отличное (но довольно продвинутое) выступление Джейка Уортона от Devoxx: Управление состоянием с помощью RxJava, Джейк Уортон

Если это проблема, как ConnectionSharingAdapter решает ее?

Наблюдаемый .establishConnection() не позволяет иметь более одной одновременной подписки из-за природы подключения и связи BLE с отслеживанием состояния (запрос-ответ — хорошо известный шаблон), а наличие более одного .subscribe(), использующего одно и то же соединение, может вызвать помехи для другого. без явного следа в коде. Вот почему BleAlreadyConnectedException был введен для пользователей, которые не следят за всеми местами в коде, где используется RxBleConnection. ConnectionSharingAdapter был представлен в качестве помощника для пользователей, которые сознательно решают разделить одно соединение между несколькими интеракторами. Если RxBleConnection сломается, ConnectionSharingAdapter распространит ошибку на все Subscriber.

Есть ли какой-нибудь чистый способ объединения всех четырех характерных операций ввода-вывода в одну .subscribe() (которая не ухудшит производительность)?

В большинстве ситуаций можно аккуратно объединить множество операций ввода-вывода. Вышеупомянутый доклад затрагивает эту тему. Правильное объединение нескольких вводов-выводов сопряжено со стоимостью дополнительных выделений, но это редко является проблемой при работе с BLE из-за низкой скорости этого канала связи.

person Dariusz Seweryn    schedule 19.06.2017
comment
Поскольку одно из моих уведомлений может создавать непрерывный поток пакетов данных, который может снизить пропускную способность BLE, я не думаю, что установление и разрыв соединения для каждого пакета будет работать. Звучит как повод для использования ConnectionSharingAdapter, не так ли? - person Robert Lewis; 20.06.2017
comment
ConnectionSharingAdapter — это просто сокращение для стандартных операторов RxJava (что можно проверить, изучив класс). Определенно связь должна сохраняться до тех пор, пока это возможно. - person Dariusz Seweryn; 20.06.2017
comment
Я также озадачен - мое приложение может выдавать множество команд BLE в разное время из-за пользовательского ввода. Как один метод subscribe() может учесть это? - person Ken DeLong; 21.06.2017
comment
Я только что добавил более продвинутый подход к реактивному программированию в репозиторий библиотеки. Не стесняйтесь проверить это — возможно, это вдохновит вас на то, как справиться с вашим вариантом использования, используя только один .subscribe(). - person Dariusz Seweryn; 23.06.2017