Почему нельзя обойтись одним видом CoroutineScope

Ответ

В Android рекомендуется использовать разные CoroutineScope для разных жизненных циклов компонентов (Activity, ViewModel и т.д.), чтобы избежать утечек памяти и корректно управлять отменой корутин.

  • Activity/Fragment Scope: lifecycleScope автоматически отменяет корутины при уничтожении компонента.
  • ViewModel Scope: viewModelScope отменяет корутины при очистке ViewModel.
  • Global Scope: GlobalScope живет всё время работы приложения и может привести к утечкам, если не управлять им вручную.

Пример с viewModelScope:

class MyViewModel : ViewModel() {
    fun fetchData() {
        viewModelScope.launch {
            // Работа с данными
        }
    }
}

Использование разных скоупов делает код безопасным и предсказуемым.

Ответ 18+ 🔞

Слушай, а вот эта вся история с корутинами в Android — это просто ёперный театр, если не разобраться. Представь: ты пишешь приложение, а оно потом память жрёт, как не в себя, и в итоге накрывается медным тазом. А всё почему? Потому что чуваки не понимают, какой CoroutineScope куда пихать.

Вот смотри, тут всё просто, как три копейки. Для каждой штуки в андроиде — свой скоуп, свой карман, куда ты эти асинхронные задачи складываешь. И главное — чтобы этот карман вовремя вытряхнули, когда он уже не нужен.

  • Для Activity или Fragment — бери lifecycleScope. Это гениально, ёпта. Создал активность — есть скоуп. Закрыл активность, пользователь ушёл — lifecycleScope берёт и отменяет ВСЕ корутины, которые в нём запущены. Автоматом! Никаких утечек памяти, потому что твоя корутина не будет впустую шаманить с уже мёртвым интерфейсом. Чистая магия, ядрёна вошь.
  • Для ViewModel — тут свой царь, viewModelScope. ViewModel же может пережить поворот экрана, да? Вот и её скоуп живёт ровно столько, сколько живет сама вьюмодель. Когда её почистят, все корутины — хоба! — отменятся. Красота.

Вот, смотри, как это выглядит в коде, простой пример:

class MyViewModel : ViewModel() {
    fun fetchData() {
        viewModelScope.launch {
            // Тут твоя работа с данными, запросы в сеть, всё дела
        }
    }
}

Запустил метод — корутина поехала в viewModelScope. Пользователь ушёл с экрана, ViewModel очистилась — и твоя фоновая работа тоже остановилась. Ничего никуда не убежало, доверия ебать ноль, но всё предсказуемо.

А теперь главный антигеройGlobalScope. Вот это, бля, чистой воды распиздяйство, если использовать его в компонентах. Он же живёт ВСЮ жизнь приложения! Ты в активити запустил через него задачу, активити умерла, а корутина себе летит дальше, как хуй с горы, и держит ссылку на всё, что успела захватить. Память течёт, приложение тормозит, потом получаешь креш — и волнение ебать, где искать причину.

Короче, мораль проще пареной репы: не выёбывайся, используй правильные скоупы. lifecycleScope для всего, что связано с экраном, и viewModelScope для бизнес-логики. А GlobalScope оставь для каких-нибудь глобальных сервисов, которые реально должны работать всегда. Тогда и память будет цела, и логика отмены прозрачна. Всё гениальное — просто, как да похуй.