Можно ли одновременно запускать два коллектора на одном CoroutineScope в Kotlin
Что проверяют
Понимаете ли вы, что collect это приостанавливающая функция, которая не вернёт управление, пока поток не закончится. Следом спрашивают, как правильно собирать несколько StateFlow из ViewModel во фрагменте и что будет, если один из коллекторов упадёт.
Как отвечать
Да, можно, но каждый коллектор должен жить в своей корутине. Два collect подряд внутри одного launch выполняются последовательно, а StateFlow и SharedFlow никогда не завершаются, поэтому до второго дело не дойдёт.
Правильный вариант во фрагменте:
viewLifecycleOwner.lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED) {
launch { viewModel.state.collect(::render) }
launch { viewModel.events.collect(::handle) }
}
}repeatOnLifecycle отменяет обе корутины при уходе в STOPPED и запускает заново при возврате, так что в фоне ничего не собирается. В Compose то же самое даёт collectAsStateWithLifecycle().
Что стоит добавить:
- холодные потоки: каждый коллектор
flow { }запускает блок заново, два коллектора означают два сетевых запроса. Чтобы делить один источник, превращайте его в горячий черезstateInилиshareIn; - ошибки: дети внутри
repeatOnLifecycleсвязаны обычнымJob, и исключение в одном коллекторе отменит соседа.SupervisorJobвviewModelScopeиlifecycleScopeкасается только корутин верхнего уровня. Ловите ошибки в самом потоке черезcatchили изолируйте веткиsupervisorScope; - общее состояние: на
Dispatchers.Mainколлекторы конкурентны, но выполняются в одном потоке, гонок нет. НаDispatchers.Defaultобщие изменяемые данные нужно защищать; - нужны оба значения сразу: тогда не два коллектора, а
combineи одинcollect.
Где спотыкаются
Пишут state.collect {} и events.collect {} друг за другом в одном launch и не понимают, почему второй поток молчит.
Собирают через lifecycleScope.launch без repeatOnLifecycle. Коллектор работает, пока экран в фоне, тратит ресурсы и трогает view, которых уже может не быть.
Не учитывают, что холодный Flow с каждым новым коллектором выполняет всю работу заново, и удивляются двойным запросам к API.