Решил я недавно заменить синхронный код, длинными макаронами оплетающий приложение, на красивую удобную асинхронщину с Flow. Сказано – сделано.
Было: макароны с проксированием информации через интерфейсы со всех концов приложения в пару мест, где и производятся целевые действия.
interface Interactor {
fun onCameraMove(mapState: MapState)
}
interactor = parentFragment.checkInstance()
interactor?.onCameraMove(mapState)
interface MapCameraMovable {
fun onCameraMove(mapState: MapState)
}
override fun onCameraMove(mapState: MapState) {
(currentFragment as? MapCameraMovable)?.onCameraMove(mapState)
}Стало: я сделал репозиторий с Flow, который асинхронно меняется в разных местах приложения, а в целевых местах он обзёрвится. Удобно и без бойлерплейта.
private val channel = Channel<MapState>(Channel.BUFFERED)
private val flow = channel.receiveAsFlow()
override fun observe(): Flow<MapState> = flow
override suspend fun once(): MapState? = flow.firstOrNull()
override suspend fun update(newMapState: MapState) = channel.send(newMapState)
Да вот только работало оно как-то странно: то правильно, то неправильно. Начал я копать:
Из-за того, что эмиты во флоу шли довольно часто, сначала подумал, что буфер у флоу переполняется. Но нет, дело не в этом. А дело было в том, что я, к своему стыду, невнимательно читал документацию:
fun <T> ReceiveChannel<T>.receiveAsFlow():
One element will be emitted to one collector only.
В итоге у меня в приложении вместо отправки одних и тех же данных нескольким подписчикам шла гонка: какой-то подписчик первый успевал получить данные, а остальным они не доставались.
Мораль: слушаете Flow в нескольких местах – используйте MutableSharedFlow.
#android #лайфхаки #рефакторинг