Как заставить cold observable в RxJava начать эмитить данные
Что проверяют
Понимаете ли вы, что cold observable это описание работы, которая запускается подпиской, и что каждая подписка запускает её заново. Следом спрашивают, как сделать, чтобы два подписчика не вызвали два сетевых запроса, то есть как превратить холодный поток в горячий.
Как отвечать
Короткий ответ: подписаться. Цепочка операторов до вызова subscribe() только собирает конвейер и ничего не выполняет. Вызов subscribe() доходит до источника, и тот начинает эмитить для этого подписчика. Подписку делают и blockingFirst(), blockingSubscribe(), test(), но блокирующие варианты уместны разве что в тестах.
Дальше то, что показывает понимание:
- ленивость источника:
Observable.just(api.load())вызоветload()сразу при сборке цепочки, до подписки. Для ленивого вызова нужныfromCallableилиdefer; - каждая подписка отдельная: два
subscribe()на холодныйSingleиз Retrofit дадут два HTTP-запроса; - общий источник:
publish()возвращаетConnectableObservable, который начинает эмитить только послеconnect().share()этоpublish().refCount(): подключается при первом подписчике и отключается, когда ушёл последний.replay(1).refCount()отдаёт опоздавшим последнее значение,cache()все значения; - потоки:
subscribeOn(Schedulers.io())задаёт, где выполняется источник,observeOn(AndroidSchedulers.mainThread())переносит результат на главный поток; - жизненный цикл:
Disposableиз подписки складывают вCompositeDisposableи очищают вonCleared()у ViewModel.
Уместно добавить, что в новом Android-коде ту же роль играют корутины: холодный Flow стартует на collect, а shareIn и stateIn делают его горячим.
Где спотыкаются
Пишут just(...) с сетевым вызовом внутри и получают запрос на главном потоке при сборке цепочки, до всякого subscribeOn.
Вызывают subscribe() без обработчика ошибок. Ошибка уходит в RxJavaPlugins.onError как OnErrorNotImplementedException и роняет приложение.
Возвращают Completable из Room или Retrofit и не подписываются на него, а потом удивляются, что запись в базу не произошла.