Какие виды скоупов существуют в Kotlin Coroutines
Что проверяют
Понимаете ли вы structured concurrency: корутина живёт внутри скоупа, и отмена скоупа отменяет всё, что в нём запущено. Следом обычно спрашивают, чем coroutineScope отличается от supervisorScope и где запускать работу, которая должна пережить экран.
Как отвечать
CoroutineScope это интерфейс с одним свойством coroutineContext, где главное это Job и диспетчер. На практике встречаются такие скоупы:
viewModelScope:SupervisorJobплюсDispatchers.Main.immediate, отменяется вonCleared(). Основное место для загрузки данных экрана;lifecycleScope: привязан кLifecycleактивити или фрагмента, отменяется приDESTROYED. Во фрагменте для работы с view берутviewLifecycleOwner.lifecycleScope, а сборFlowоборачивают вrepeatOnLifecycle(Lifecycle.State.STARTED);rememberCoroutineScope(): в Compose, отменяется, когда composable уходит из композиции;MainScope()иCoroutineScope(context): ручное создание, вызватьcancel()обязаны вы сами. Так делают скоуп уровня приложения и отдают его через DI;GlobalScope: ни к чему не привязан, помечен@DelicateCoroutinesApi, в прикладном коде не нужен;coroutineScope {}иsupervisorScope {}: suspend-функции, которые создают вложенный скоуп и ждут всех детей. В первом ошибка одного ребёнка отменяет остальных, во втором нет.
runBlocking блокирует поток, место ему в main и старых тестах, в тестах сейчас принят runTest. Работу, которая должна пережить закрытие приложения, скоупом не решают, это задача WorkManager.
Где спотыкаются
Собирают Flow в lifecycleScope.launch без repeatOnLifecycle. Сбор продолжается, пока приложение свёрнуто, и тратит ресурсы.
Оборачивают suspend-вызовы в catch (e: Exception) и глотают CancellationException, после чего отменённая корутина продолжает работать.
Считают, что MainScope гарантирует выполнение на главном потоке. Это лишь диспетчер по умолчанию, withContext(Dispatchers.IO) внутри корутины уводит код на другой поток.