🌪 Ваша дата в опасности: flatMapConcat vs Merge vs Latest
Вам нужно взять поток ID-шников и для каждого скачать детали из сети. Задача банальная:
val detailsFlow = idsFlow.flatMap??? { id ->
repository.fetchDetailsAsFlow(id)
}
IDE услужливо подсказывает три варианта: Concat, Merge, Latest. И вот тут кроется разница между "работает как часы", "тормозит" и "тихо теряет данные".
Давайте разберем на пальцах.
1. flatMapConcat (Очередь в поликлинику)
• Как работает: Строго последовательно. Ждет, пока полностью завершится внутренний Flow для первого ID, и только потом переходит ко второму.
• Плюс: Сохраняет идеальный порядок элементов. Безопасно для транзакций/БД.
• Минус (Bottleneck): Это ОЧЕНЬ медленно. Если у вас 10 картинок, и каждая качается по секунде - весь процесс займет 10 секунд. Никакой параллельности.
2. flatMapMerge (Броуновское движение)
• Как работает: Запускает сбор внутренних Flow параллельно. Не ждет окончания предыдущего.
• Плюс: Максимальная скорость. 10 картинок скачаются (почти) за 1 секунду.
• Минус: Порядок ответов непредсказуем. Если вам важно, чтобы элементы пришли в том же порядке, что и ушли — вы получите race condition.
• 🧠 Секрет Сеньора: У него есть параметр concurrency (по дефолту 16). Если поставить flatMapMerge(concurrency = 1), он превратится в flatMapConcat.
3. flatMapLatest (Амнезия)
• Как работает: Как только в верхний (внешний) поток прилетает новый элемент, он отменяет выполнение предыдущего внутреннего потока.
• Плюс: Идеально для UI (например, строка поиска). Юзер ввел "A" -> пошел запрос. Ввел "AB" -> запрос для "A" отменился (вылетел CancellationException), пошел запрос для "AB". Экономит трафик и ресурсы.
• Фатальный Минус: НИКОГДА не используйте это для сохранения данных или платежей. Если вы отправите два события на сохранение подряд, первое будет убито на полпути.
📝 Чек-лист для код-ревью:
✅ Поиск с автокомплитом? -> flatMapLatest
✅ Скачивание списка файлов, порядок не важен? -> flatMapMerge
✅ Строгая последовательная обработка платежей или логов? -> flatMapConcat