Ответы на самые частые вопросы по RxJava

1.Какому «паттерну поведения» следует RxJava? Push или Pull?

В RxJava новые данные «заталкиваются»(Push) к наблюдателям

2.Какова разница между колбэками onNext(), onComplete() and onError()?

Эти колбэки которые получают Observable / Flowable. onNext() отрабатывает для каждой эмиссии данных. onComplete() и onError() взаимоисключаемы. Первый отработает когда эмиссия данных завершилась, а второй если произошла ошибка.

3.Сколько раз колбэки onNext(), onComplete() and onError() могут быть вызваны?

onNext() – от 0 до бесконечного кол-ва раз
onComplete() – максимум один раз за поток
onError() – максимум один раз за поток

4.Когда Observable начинает эмиссию частей данных?

Есть 2 вида Observable — «холодные» и «горячие». Холодные начинают эмиссию данных только тогда когда на них кто-нибудь подпишется. Горячие же эмитят данные вне зависимости от того есть ли подписант или нет.

5. Какая разница между «холодными» и «горячими» Observables

В том что они эмитят данные по разному. Холодные создаются множество раз и каждого инстанса могут подключены разные слушатели(подписанты), с разной логикой. Горячие же похоже на «поток» событий — разные слушатели могут подписываться на горячий observable, но такой observable создается один раз.

6. Можно ли трансформировать «холодный» Observable в «горячий»?

Можно используя операторы publish().connect() . publish() трансформирует обычный Observable в ConnectableObservable, который имеет повадки «горячего». Сразу после того как будет задействован оператор connect() трансформированный Observable начнет эмитить данные вне зависимости от того есть подписчики или нет.

Другой метод трансформации это обернуть Observable Subject-ом. В данном случае Subject подписывается на «холодный» Observable незамедлительно и раскрывает себя как Observable для будущих подписчиков. Опять же, работа выполняется независимо от того, есть ли какие-либо подписчики или нет, с другой стороны, несколько подписчиков Subject-а не будут инициировать начальную эмиссию данных несколько раз.

7. Можно ли трансформировать «горячий» observable в «холодный»?

Можно несколькими путями. Первый подход — использование оператора defer(). Этот оператор откладывает создание «горячего» Observable, поэтому каждый новый подписчик снова запускает работу.

8. Что такое Планировщик (Scheduler)? Как RxJava использует их?

По умолчанию RxJava использует один поток — все операции выполняются на одном потоке. Планировщик помогает переключить выполнение определенного блока кода в иной поток.

9. Что такое цепочка-Observable?

Список операций / преобразований, выполненных между источником и конечным подписчиком. Простой пример — создание объекта User, фильтрация пользователей-администраторов оператором filter(), проверка их подлинности оператором filter() и, наконец, полное имя
оператором map().

10. Какая разница между операторами observeOn() и subscribeOn()?

subscribeOn() — используется для того, чтобы указать планировщику на каком потоке будет проходить основная работа. Например, очень тяжелые вычисления, которые могут затормозить UI-поток, можно перенести в рабочий поток используя данный оператор. Пример: subscribeOn(Schedulers.newThread())

observeOn() — указывает планировщику поток, на котором будут выполняться все последующие операции. Другими словами, он меняет поток для всех операторов после него. Например, после тяжелых вычислений на рабочем потоке, нужно показать результат на UI-потоке. Здесь мы можем написать observeOn(AndroidSchedulers.mainThread())

11. Что будет если много раз выполнить оператор subscribeOn() в цепочке?

Только первый оператор даст желаемый эффект. Остальные же эффекта не дадут, кроме траты ресурсов.

12. Что будет если много раз выполнить оператор observeOn() в цепочке?

Каждый observeOn() включает планировщик (поток), в котором будут выполняться все последующие операторы. Сложные потоки RxJava могут выиграть от нескольких операторов observeOn().

13. Какая разница между операторами map() и flatMap()?

Оператор map() просто превращает(мэппит) ЗначениеА в ЗначениеБ. Например: объекты в списке типа Int превратить в объект типа String Обрабатываются уже готовые/полученные значения.

Оператор flatMap() позволяет превращать-оборачивать получаемые значения в новые потоки данных. Например, если получаем из одного потока строку(типа URL) СтрокаБ, то эту строку мы можем превратить в новый поток. Если Поток<СтрокаБ> испускает несколько элементов, все они в конечном итоге будут переданы исходному наблюдателю (будут «сведены» к одному Observer-у).
Поскольку нет никаких ограничений на Поток<СтрокаБ>, flatMap() полезен для развертывания параллелизма в выполнении задач.

14. Какая разница между операторами flatMap(), concatMap() и switchMap()?

Оператор flatMap() — как мы говорили выше — может разделить цепочку выполнения на несколько промежуточных потоков, а результаты будут получены Observer-ом. Следует отметить, что порядок получения результатов будет в соответствии с тем какой результат был получен первым.

Оператор concatMap() работает также как flatMap(), но только сохраняет порядок выполнения потоков. Из-за этого выполнение этого оператора может занять больше времени.

Оператор switchMap() тоже чем-то похож на flatMap(), но с единственным исключением — при получении нового элемента из цепочки предыдущие потоки созданные из предыдущих элементов уничтожаются. Проще говоря, используя данный оператор активным будет только последний Observable из последнего полученного элемента. Стало быть результат выполнения получим только самого последнего Observable.