rxjava что это такое
Введение в RxJava: Почему Rx?
Этот цикл статей предназначен для знакомства начинающего реактивного программиста с мощью библиотеки RxJava — реализации принципов реактивного программирования для JVM. Это перевод обширного туториала по RxJava Крисса Фруссиоса, основанного на IntroToRx для Rx.NET.
Для следования этой обучающей программе от вас не потребуются знания реактивного или функционального программирования, однако, предполагается наличие базовых знаний Java.
Материал этих статей расчитан на прочтение от начала до конца. Его обьем больше, чем среднего туториала, но меньше чем реальной книги. Мы начнем с самых основ и от раздела к разделу будем переходить к всё более продвинутым сценариям и концепциям. Каждый раздел задумывался самодостаточным и лаконичным для того, чтобы к нему можно было вернуться в будущем.
Примеры к этим материалам доступны в двух видах:
Содержание:
Часть первая – Вступление: Почему Rx?
Пользователи ожидают данных в реальном времени. Они хотят твиты сейчас. Подтвержение заказа сейчас. Им необходимы цены по состоянию на сейчас. Как разработчик, вы нуждаетесь в самонаводящихся сообщениях. Вы не хотите быть блокированным в ожидании результата. Вы хотите, чтобы результат пришел к вам по готовности. Даже более того, вы хотите работать с результатом по частям: вы не хотите ждать пока загрузится всё перед тем как отобразить первую строку. Мир перешел в режим уведомлений. У разработчиков есть инструменты, чтобы уведомлять, это легко. Им нужны инструменты чтобы реагировать на уведомления.
Добро пожаловать в Rx. Rx – это мощный инструмент, который позволяет решать проблемы в элегантном декларативном стиле, присущем функциональному программированию. Rx обладает следующими преимуществами:
Когда следует использовать Rx?
Rx применяется для составления и обработки последовательностей событий.
Следует использовать Rx
Возможно использование Rx
Не следует использовать Rx
В следующей части мы рассмотрим фундаментальные типы, на которых основана концепция реактивного программирования: Observable и Observer.
Теперь у проекта есть свой публичный репозиторий и любой желающий может присоединится к созданию углубленного русскоязычного туториала по Rx. Перевод этой части уже там, остальные появятся в скором времени, а с вашей помощью, еще быстрее.
Грокаем* RxJava, часть первая: основы
* от переводчика: я долго думал над тем, как перевести на русский язык глагол «to grok». С одной стороны, это слово переводится как «понять» или «осознать», а с другой стороны, при переводе романа Роберта Хайнлайна «Чужак в чужой стране» (в котором это слово впервые и появилось на свет), переводчики сделали из него русское «грокать». Роман я не читал, поэтому счёл, что есть у этого слова какие-то смысловые оттенки, которые русскими аналогами не передавались, а посему в своём переводе использовал ту же самую кальку с английского.
RxJava — это, сейчас, одна из самых горячих тем для обсуждения у Android-программистов. Единственная проблема состоит в том, что понять самые её основы, если вы не сталкивались ни с чем подобным, может быть довольно затруднительно. Функциональное реактивное программирование довольно сложно понять, если вы пришли из императивного мира, но, как только вы разберётесь с ним, вы поймёте, насколько же это круто!
Я постараюсь дать вам некое общее представление об RxJava. Задача этого цикла статей состоит не в том, чтобы объяснить всё вплоть до последней запятой (вряд ли я смог бы это сделать), но, скорее в том, чтобы заинтересовать вас RxJava, и тем, как она работает.
Основы
Здравствуй, мир!
Давайте разберёмся с небольшим примером. Сначала создадим простой Observable :
Наш Observable порождает строку «Hello, world!», и завершает свою работу. Теперь создадим Subscriber для того, чтобы принять данные и что-нибудь с ними сделать.
Упрощаем код
Теперь давайте избавимся от переменных, прибегнув к цепочечному вызову методов:
Ну и, наконец, мы можем воспользоваться лямбдами из Java 8, чтобы упростить код ещё больше:
Если вы пишете под Android (и поэтому не можете использовать Java 8), я очень рекомендую retrolambda, которая поможет упростить очень уж многословный в некоторых местах код.
Трансформация
Давайте попробуем нечто новое.
Например, я хочу добавить свою подпись к «Hello, world!», выводимому в консоль. Как это сделать? Во-первых, мы можем изменить наш Observable :
Такой вариант тоже является неподходящим, но уже по другим причинам: я хочу, чтобы мои подписчики были настолько легковесными, насколько это возможно, так как я могу запускать их в главном потоке. На более концептуальном уровне, подписчики должны реагировать на поступающие в них данных, а не изменять их.
Было бы здорово, если можно было изменить «Hello, world!» на некотором промежуточном шаге.
Введение в операторы
И снова можно прибегнуть к лямбдам:
Ещё кое-что о map()
Интересно: мы начали со строк, а наш Subscriber принимает Integer. Кстати, мы опять забыли о лямбдах:
Взгляните на это — наши Observable и Subscriber теперь выглядят так же, как и в самом начале! Мы просто добавили несколько промежуточных шагов, трансформирующих наши данные. Мы могли бы даже снова добавить код, прибавляющий мою подпись к порождаемым строкам:
И что дальше?
Сейчас вы наверное думаете: «Ну как обычно: показывают простецкий пример, и говорят, что технология крутая, потому что она позволяет решить эту задачу в две строчки кода». Согласен, пример и правда простой. Но из него можно вынести пару полезных идей:
Идея №1: Observable и Subscriber могут делать всё, что угодно
Не ограничивайте своё воображение, возможно всё, чего вы хотите.
Ваш Observable может быть запросом к базе данных, а Subscriber может отображать на экране результаты запроса. Observable может также быть кликом по экрану, Subscriber может содержать в себе реакцию на этот клик. Observable может быть потоком байтов, принимаемых из сети, тогда как Subscriber может писать эти данные на устройство хранения данных.
Это фреймворк общего назначения, способный справиться почти с любой проблемой.
Идея №2: Observable и Subscriber не зависят от промежуточных шагов, находящихся между ними
Почему следует использовать RxJava в Android – краткое введение в RxJava
Мы продолжаем знакомить вас с нашим издательским поиском, и хотели прозондировать общественное мнение на тему RxJava.
В ближайшее время собираемся опубликовать более общий материал по реактивному программированию, которое нас также интересует не первый год, а сегодня предлагаем почитать о применении RxJava в Android, так как именно на этой платформе особенно важна динамичность и быстрота реагирования. Добро пожаловать под кат
В большинстве приложений Android мы реагируем на действия пользователя (щелчки, смахивание, т.д.), а тем временем в фоновом режиме идет какая-то другая работа (сетевая).
Оркестровка всех этих процессов – сложная задача, любой код рискует быстро превратиться в бесформенную кашу.
Например, не так просто послать по сети запрос к базе данных, а после его выполнения сразу начать одновременно выбирать и пользовательские сообщения, и настройки, а после завершения всей этой работы вывести приветственное сообщение.
Именно в таких случаях как нельзя кстати будет RxJava (ReactiveX) – библиотека, позволяющая соорганизовать множество действий, обусловленных определенными событиями в системе.
Работая с RxJava, можно будет забыть об обратных вызовах и адском управлении глобальным состоянием.
Вернемся к нашему примеру:
послать по сети запрос к базе данных, а после его выполнения сразу начать одновременно выбирать и пользовательские сообщения, и настройки, а после завершения всей этой работы вывести приветственное сообщение.
Если разобрать эту ситуацию подробнее, найдем в ней три основных этапа, причем все три происходят в фоновом режиме:
Чтобы сделать то же самое в Java SE и Android, нам бы потребовалось:
Уже понятно, что для этого требуется управлять состоянием, а также задействовать некоторые механизмы блокировки, существующие в Java.
Всего этого можно избежать, работая с RxJava (см. примеры ниже) – весь код выглядит как поток, расположенный в одном месте и строится на базе функциональной парадигмы (см. здесь).
Быстрый запуск в Android
Чтобы получить библиотеки, которые, скорее всего, понадобятся вам для проекта, вставьте в ваш файл build.gradle следующие строки:
Таким образом будут включены:
Здесь мы создали Observable, который сгенерирует два элемента — 1 и 2.
Мы подписались на observable, и теперь, как только элемент будет получен, мы выведем его на экран.
Объект Observable – такая сущность, на которую можно подписаться, а затем принимать генерируемые Observable элементы. Они могут создаваться самыми разными способами. Однако Observable обычно не начинает генерировать элементы, пока вы на них не подпишетесь.
После того, как вы подпишетесь на observable, вы получите Subscription (подписку). Подписка будет принимать объекты, поступающие от observable, пока он сам не просигнализирует, что завершил работу (не поставит такую отметку), либо (в очень редких случаях) прием будет продолжаться бесконечно.
Более того, все эти действия будут выполняться в главном потоке.
Управление сложным потоком
Помните сложный поток, описанный нами в самом начале?
Вот как он будет выглядеть с RxJava:
В таком случае будет создан новый пользователь (createNewUser()), и на этапе его создания и возвращения результата в то же самое время продолжится выбор пользовательских сообщений (fetchUserMessages()) и пользовательских настроек (fetchUserSettings). Мы дождемся завершения обоих действий и возвратим скомбинированный результат (Pair.create()).
Не забывайте – все это происходит в отдельном потоке (в фоновом режиме).
Затем программа выведет на экран полученные результаты. Наконец, список сообщений будет приспособлен еще в один observable, который будет выводить сообщения поодиночке, а не целым списком, причем каждое сообщение будет появляться в окне терминала.
Работать с RxJava будет гораздо проще, если вы знакомы с функциональным программированием, в частности, с концепциями map и zip. Кроме того, в RxJava и ФП очень похоже выстраивается обобщенная логика.
Как создать собственный observable?
Если код становится в значительной степени завязан на RxJava (например, здесь ), то зачастую вам придется писать собственные observable, так, чтобы они укладывались в логику вашей программы.
А вот похожий вариант, не требующий выполнять действие строго в конкретном потоке:
Здесь важно отметить три метода:
Кроме того, вероятно, будет удобно пользоваться RxJavaAsyncUtil.
Интеграция с другими библиотеками
По мере того, как RxJava становится все популярнее и де-факто превращается в стандарт асинхронного программирования в Android, все больше библиотек все в большей мере интегрируются с ней.
Всего несколько примеров:
Retrofit — «Типобезопасный HTTP-клиент для Android и Java»
SqlBrite — «Легкая обертка для SQLiteOpenHelper, обогащающая SQL-операции семантикой реактивных потоков.»
StorIO — «Красивый API для SQLiteDatabase и ContentResolver»
Все эти библиотеки значительно упрощают работу с HTTP-запросами и базами данных.
Интерактивность с Android UI
Это введение было бы неполным, если бы мы не рассмотрели, как использовать нативные UI-элементы в Android.
Очевидно, можно просто положиться на setOnClickListener, но в долгосрочной перспективе RxBinding может подойти вам лучше, поскольку позволяет подключить UI к общему потоку RxJava.
Практика показывает, что при работе с RxJava следует придерживаться некоторых правил.
Всегда использовать обработчик ошибок
Пропускать обработчик ошибок таким образом
обычно не следует. Исключение, выбрасываемое в наблюдателе или в одном из действий будет выброшено исключение, которое, скорее всего, убьет вам все приложение.
Еще лучше было бы сделать обобщенный обработчик:
Извлекать методы действий
Если у вас будет много внутренних классов, то через некоторое время удобочитаемость кода может испортиться (особенно если вы не работаете с RetroLambda).
выглядел бы лучше после такого рефакторинга:
Использовать собственные классы или кортежи
Бывают случаи, в которых некое значение определяется другим значением (например, пользователь и пользовательские настройки), и вы хотели бы получить оба этих значения при помощи двух асинхронных запросов.
В таких случаях рекомендую использовать JavaTuples.
Управление жизненным циклом
Зачастую бывает так, что фоновый процесс (подписка) должен просуществовать дольше, чем активность или фрагмент, в котором (которой) он содержится. Но что если результат вас уже не интересует, как только пользователь покинет активность?
В таких случаях вам поможет проект RxLifecycle.
Оберните ваш observable вот так (взято из документации) и сразу после его разрушения выполнится отписка:
Конечно, это далеко не полное руководство об использовании RxJava в Android, но, надеюсь, смог вас убедить, что в некоторых отношениях RxJava лучше обычных AsyncTask.
Реактивное программирование с RxJava и RxKotlin
Russian (Pусский) translation by Liliya (you can also view the original English article)
С тех пор, как стал официально поддерживаемым языком для разработки Android, Kotlin быстро завоевал популярность среди разработчиковAndroid, и Google сообщает о 6-кратном увеличении приложений, созданных с помощью Kotlin.
Использование RxJava с Kotlin может помочь вам создавать высокореактивные приложения в меньшем количестве кодов, но язык программирования не идеален, поэтому я также буду обмениваться обходным решением проблемы конверсии SAM, с которой сталкиваются многие разработчики, когда они впервые начинают использовать RxJava 2.0 с Kotlin.
Чтобы обернуть все, мы создадим приложение, демонстрирующее, как вы можете использовать RxJava для решения некоторых проблем, с которыми вы сталкиваетесь в реальных проектах Android.
Если вы первый раз пробуете RxJava, то по пути я также буду предоставлять всю справочную информацию, необходимую для понимания основных концепций RxJava. Даже если вы никогда не экспериментировали с RxJava раньше, в конце этой статьи вы будете иметь четкое представление о том, как использовать эту библиотеку в своих проектах, и вы создали несколько рабочих приложений,используя RxJava, RxKotlin, RxAndroid и RxBinding.
Что такое RxJava, во всех случаях?
За небольшим опытом использования приложений RxJava для Android вы можете ознакомиться с некоторыми другими моими сообщениями здесь, на Envato Tuts +.
Итак, как работает RxJava?
RxJava расширяет шаблон разработки программного обеспечения Observer, основанный на концепции наблюдателей и наблюдаемых. Чтобы создать базовый конвейер данных RxJava, вам необходимо:
RxJava позволяет преобразовывать эти события onClick в поток данных, который затем можно манипулировать с помощью различных операторовRxJava. В этом конкретном примере вы можете использовать оператор debounce() для фильтрации данных, которые происходят в быстрой последовательности,поэтому, даже если пользователь нажимает на кнопку «Оплатить сейчас», ваше приложение будет регистрировать только на один платеж.
Каковы преимущества использования RxJava?
Мы видели, как RxJava может помочь вам решить определенную проблему в конкретном приложении, но что он должен предлагать проектам Android в целом?
RxJava может упростить ваш код, предоставив вам способ написать то, что вы хотите достичь, вместо того, чтобы писать список инструкций, которые должны выполнять ваше приложение. Например, если вы хотите игнорировать все данные, которые происходят в течение одного и того же 500-миллисекундного периода, тогда вы должны написать:
Кроме того, поскольку RxJava обрабатывает почти все как данные, он предоставляет шаблон, который вы можете применить к широкому спектру событий: создать Observable, создать Observer, подписать Observer к наблюдаемому, проверить и повторить. Этот формульный подход дает гораздо более простой, удобочитаемый код.
Другим важным преимуществом для разработчиков Android является то, что RxJava может сильно пострадать от много поточности на Android.Сегодняшние мобильные пользователи ожидают, что их приложения смогут бытьмногозадачными, даже если это так просто, как загрузка данных в фоновом режиме,оставаясь при этом зависящей от пользовательского ввода.
Android имеет несколько встроенных решений для создания и управления несколькими потоками, но ни один из них не прост в реализации, и они могут быстро привести к сложному коду, который трудно читать и который подвержен ошибкам.
В RxJava вы создаете и управляете дополнительными потоками, используя комбинацию операторов и планировщиков. Вы можете легко изменить поток, в котором выполняется работа, используя оператор subscribeOn плюс планировщик. Например, здесь мы планируем работу над новым потоком:
По сравнению с встроенными многопоточными решениями Android, подход RxJava гораздо более краток и понятен.
Опять же, вы можете узнать больше о том, как работает RxJava, и о преимуществах добавления этой библиотеки в ваш проект в статье«Начало работы с RxJava 2 для Android».
Должен ли я использовать RxJava или RxKotlin?
Поскольку Kotlin на 100% совместим с Java, вы можете использовать большинство библиотек Java в своих проектах Kotlin без каких-либо трудностей, а библиотека RxJava не является исключением.
Существует специальная библиотека RxKotlin, которая представляет собой обертку Kotlin вокруг обычной библиотеки RxJava. Эта оболочка предоставляет расширения, которые оптимизируют RxJava для среды Kotlinи могут дополнительно уменьшить количество кода шаблона, который вам нужно написать.
Поскольку вы можете использовать RxJava в Kotlin, не требуя RxKotlin, мы будем использовать RxJava в этой статье, если не указано иное.
Создание простых наблюдателей и наблюдаемых в Kotlin
Наблюдатели и наблюдаемые являются строительными блоками RxJava, поэтому давайте начнем с создания:
Создайте новый проект с настройками по вашему выбору, но при появлении запроса установите флажок Включить поддержку Kotlin. Затем откройте файл build.gradle вашего проекта и добавьте библиотеку RxJava в зависимости от проекта:
Затем откройте файл activity_main.xml вашего проекта и добавьте кнопку, которая начнет поток данных:
Существует несколько способов создания Observable, но одним из самых простых является использование оператора just() для преобразования объекта или списка объектов в Observable.
Теперь вы можете проверить это приложение:
На этом этапе Observable начнет выдавать свои данные, и Observer будет печатать свои сообщения в Logcat. Вывод Logcat должен выглядеть примерно так:
Вы можете загрузить этот проект из GitHub, если хотите попробовать его сами.
Kotlin Extensions для RxJava
Теперь, когда мы увидели, как настроить простой RxJava-конвейер в Kotlin, давайте посмотрим, как вы можете добиться этого в меньшем коде, используя функции расширения RxKotlin.
Чтобы использовать библиотеку RxKotlin, вам нужно добавить ее как зависимость от проекта:
Вот результат, который вы должны увидеть:
Решение проблемы неоднозначности SAM RxJava
RxKotlin также обеспечивает важное обходное решение для проблемы с преобразованием SAM, которое может возникать при наличии нескольких перегрузок параметров SAM для данного метода Java. Эта двусмысленность SAM смущает компилятор Kotlin, поскольку он не может решить, какой интерфейс он должен преобразовать, и ваш проект не сможет получить результат.
Эта двусмысленность SAM является особой проблемой при использовании RxJava 2.0 с Kotlin, так как многие операторы RxJava принимают несколько SAM-совместимых типов.
Давайте рассмотрим проблему преобразования SAM в действии. В следующем коде мы используем оператор zip() для объединения вывода двух наблюдаемых:
Вот результат этого кода:
Заключение
В этом уроке я показал вам, как начать использовать библиотеку RxJava в проектах Kotlin, в том числе с использованием ряда дополнительных поддерживающих библиотек, таких как RxKotlin и RxBinding. Мы рассмотрели, как вы можете создавать простые наблюдатели и наблюдаемых в RxKotlin, чтобы оптимизировать RxJava для платформы Kotlin, используя функции расширения.
До сих пор мы использовали RxJava для создания простых Observables, которые излучают данные, и наблюдателей, которые печатают эти данные в Logcat Android Studio, но это не то, как вы будете использовать RxJava в реальном мире!
В следующем посте мы рассмотрим, как RxJava может помочь решить реальные проблемы, с которыми вы столкнетесь при разработке приложений для Android. Мы будем использовать RxJava с Kotlin для создания классического экрана регистрации.
Введение в RxJava: Ключевые типы
Содержание:
Ключевые типы
Rx базируется на двух фундаментальных типах, в то время, как некоторые другие расширяют их функциональность. Этими базовыми типами являются Observable и Observer, которые мы и рассмотрим в этом разделе. Мы также рассмотрим Subject’ы – они помогут в понимании основных концепций Rx.
Observable
Observable – первый базовый тип, который мы рассмотрим. Этот класс содержит в себе основную часть реализации Rx, включая все базовые операторы. Мы рассмотрим их позже, а пока нам следует понять принцип работы метода subscribe. Вот ключевая перегрузка [2]:
Метод subscribe используется для получения данных выдаваемых [3] observable. Эти данные передаются наблюдателю, который предполагает их обработку в зависимости от требований потребителя. Наблюдатель в этом случае является реализацией интерфейса Observer.
Observer
В Rx предусмотрена абстрактная реализация Observer, Subscriber. Subscriber реализует дополнительную функциональность и, как правило, именно его следует использовать для реализации Observer. Однако, для начала, рассмотрим только интерфейс:
Эти три метода являются поведением, которое описывает реакцию наблюдателя на сообщение от observable. onNext у наблюдателя будет вызван 0 или более раз, опционально сопровождаясь onCompleted или onError. После них вызовов больше не будет.
Разрабатывая код с помощью Rx, вы увидите много Observable, но намного меньше Observer. И хотя и необходимо понимать концепцию Observer, существуют способы не требующие непосредственного создания его экземпляра.
Реализация Observable и Observer
Вы можете вручную реализовать Observer и Observable. В реальности в этом, как правило, нет необходимости: Rx предоставляет готовые решения, чтобы упростить разработку. Это также может быть не совсем безопасно, поскольку взаимодействие между частями библиотеки Rx включает в себя принципы и внутреннюю инфраструктуру, которые могут быть не очевидны новичку. В любом случае, будет проще для начала использовать множество инструментов уже предоставленных библиотекой для создания необходимого нам функционала.
Чтобы подписаться на observable, совсем нет необходимости в реализации Observer. Существуют другие перегрузки метода subscribe, которые принимают в качестве аргументов соответствующие функции для onNext, onError и onSubscribe, инкапсулирующие создание экземпляра Observer. Предоставлять их всех тоже не обязательно, вы можете описать только часть из них, например, только onNext или только onNext и onError.
Лямбда-выражения в Java 1.8 делают эти перегрузки очень подходящими для использования в коротких примерах этой серии статей.
Subject
Subject’ы являются расширением Observable, одновременно реализуя интерфейс Observer. Идея может показаться странной, но в определенных случаях они делают некоторые вещи намного проще. Они могут принимать сообщения о событиях (как observer) и сообщать о них своим подписчикам (как observable). Это делает их идеальной отправной точкой для знакомства с Rx кодом: когда у вас есть данные, поступающие извне, вы можете передать их в Subject, превращая их таким образом в observable.
Существует несколько реализаций Subject. Сейчас мы рассмотрим самые важные из них.
PublishSubject
PublishSubject – самая простая реализация Subject. Когда данные передаются в PublishSubject, он выдает их всем подписчикам, которые подписаны на него в данный момент.
Как мы видим, 1 не была напечатана из-за того, что мы не были подписаны в момент когда она была передана. После того как мы подписались, мы начали получать все значения поступающие в subject.
ReplaySubject
ReplaySubject имеет специальную возможность кэшировать все поступившие в него данные. Когда у него появляется новый подписчик, последовательность выдана ему начиная с начала. Все последующие поступившие данные будут выдаваться подписчикам как обычно.
Все значения были получены, не смотря на то, что один из подписчиков подписался позже другого. Обратите внимание, что до того как получить новое значение, подписчик получает все пропущенные. Таким образом, порядок последовательности для подписчика не нарушен.
Кэшировать всё подряд не всегда лучшая идея, так как последовательности могут быть длинными или даже бесконечными. Фабричный метод ReplaySubject.createWithSize ограничивает размер буфера, а ReplaySubject.createWithTime время, которое объекты будут оставаться в кеше.
Наш подписчик на этот раз пропустил первое значение, которое выпало из буфера размером 2. Таким же образом со временем из буфера выпадают объекты у
Subject созданного при помощи createWithTime.
Создание ReplaySubject с ограничением по времени требует объект планировщика (Scheduler), который является представлением времени в Rx. Мы обязательно вернемся к планировщикам в разделе про многопоточность.
ReplaySubject.createWithTimeAndSize ограничивает буфер по обоим параметрам.
BehaviorSubject
BehaviorSubject хранит только последнее значение. Это то же самое, что и ReplaySubject, но с буфером размером 1. Во время создания ему может быть присвоено начальное значение, таким образом гарантируя, что данные всегда будут доступны новым подписчикам.
Начальное значение предоставляется для того, чтобы быть доступным еще до поступления данных.
Так как роль BehaviorSubject – всегда иметь доступные данные, считается неправильным создавать его без начального значения, также как и завершать его.
AsyncSubject
AsyncSubject также хранит последнее значение. Разница в том, что он не выдает данных до тех пока не завершится последовательность. Его используют, когда нужно выдать единое значение и тут же завершиться.
Обратите внимание, что если бы мы не вызвали s.onCompleted(), этот код ничего бы не напечатал.
Неявная инфраструктура
Как мы уже упоминали, существуют принципы, которые могут быть не очевидны в коде. Один из важнейших заключается в том, что ни одно событие не будет выдано после того, как последовательность завершена (onError или onCompleted). Реализация subject’ уважает эти принципы:
Безопасность не может быть гарантирована везде, где используется Rx, поэтому вам лучше быть осведомленным и не нарушать этот принцип, так как это может привести к неопределенным последствиям.
В продолжении мы рассмотрим жизненный цикл Observable.
[1] Или знакомые всем Event Listeners. – Примеч. Автора
[2] Я, все-таки считаю, что ключевой перегрузкой тут является именно версия с Observer в качестве аргумента, в оригинале в качестве примера приводится версия subscribe(Subscriber subscriber) – Примеч. Автора
[3] Я буду использовать слово «выдавать» чтобы описать событие передачи данных от Observable Observer’у (to emit в ориг.). – Примеч. Автора
[4] Автор использует термин последовательность (sequence), чтобы обозначить множество всех данных, которые может выдать Observable. – Примеч. Автора