← Назад к вопросам

Как Scope выглядит в коде

2.2 Middle🔥 142 комментариев
#Dependency Injection#Архитектура и паттерны

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Scope в коде Android/Kotlin: практическое воплощение

В коде Scope (область видимости) — это не абстракция, а конкретный объект, реализующий интерфейс CoroutineScope, который определяет контекст и жизненный цикл корутин. Его основная задача — отвечать на вопрос: «Когда и при каких условиях должны быть отменены все запущенные в этом Scope корутины?».

Базовый вид Scope в коде

Минимальная реализация Scope требует предоставления CoroutineContext, ключевым элементом которого является Job.

// 1. Создание кастомного Scope вручную
val myCustomScope = object : CoroutineScope {
    override val coroutineContext: CoroutineContext
        get() = Job() + Dispatchers.IO // Job + диспетчер
}

// Запуск корутины внутри этого Scope
myCustomScope.launch {
    delay(1000)
    println("Работает в myCustomScope")
}

Scope в архитектурных компонентах Android

В Android разработке Scope напрямую связаны с жизненным циклом компонентов. Google предоставляет готовые реализации через KTX-библиотеки.

// 2. ViewModelScope - самый распространённый пример
class MyViewModel : ViewModel() {
    fun fetchData() {
        // Эта корутина привязана к жизненному циклу ViewModel
        viewModelScope.launch {
            // Будет автоматически отменена при очистке ViewModel (onCleared)
            val data = repository.loadData()
            _uiState.value = data
        }
    }
}

// 3. LifecycleScope - привязка к LifecycleOwner (Activity, Fragment)
class MyFragment : Fragment() {
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        // Запуск с привязкой к разным фазам lifecycle
        lifecycleScope.launch {
            // Будет отменён при уничтожении lifecycle
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                // этот блок выполняется только когда Lifecycle в состоянии STARTED или выше
                collectUiState()
            }
        }

        // Или более простой вариант:
        viewLifecycleOwner.lifecycleScope.launch {
            // Корректная отмена при уничтожении View фрагмента
            updateUI()
        }
    }
}

Структура и композиция Scope

Scope часто создаются с помощью фабричных функций, которые задают их поведение:

// 4. Создание Scope с SupervisorJob и настройками
val supervisorScope = CoroutineScope(
    SupervisorJob() + // Позволяет дочерним корутинам падать независимо
    Dispatchers.Main.immediate + // Основной диспетчер
    CoroutineName("NetworkScope") + // Имя для отладки
    CoroutineExceptionHandler { _, throwable -> // Обработчик ошибок
        Log.e("MyScope", "Необработанное исключение", throwable)
    }
)

// 5. Scope для определённого слоя приложения
class NetworkService(
    private val externalScope: CoroutineScope // Инжектированный Scope
) {
    suspend fun fetchWithTimeout() = withTimeout(5000) {
        // Используем внешний Scope для контроля жизненного цикла
        externalScope.coroutineContext // Используем контекст внешнего Scope
    }
}

Ключевые визуальные признаки Scope в коде:

  1. Объявление как свойства класса:
class MyComponent {
    private val ioScope = CoroutineScope(Dispatchers.IO + SupervisorJob())
    // или
    private val mainScope = MainScope() // Готовый Scope от Google
}
  1. Реализация интерфейса CoroutineScope: Любой класс может стать Scope, реализовав единственное свойство coroutineContext.

  2. Использование фабричных функций:

// Наиболее распространённые создания Scope
val scope1 = CoroutineScope(Dispatchers.Default)
val scope2 = MainScope() // Dispatchers.Main + Job
val scope3 = viewModelScope // внутри ViewModel
  1. Методы управления жизненным циклом:
fun cleanup() {
    // Явная отмена всех корутин в Scope
    myScope.cancel()
    
    // Или отмена с причиной
    myScope.cancel("Пользователь вышел из экрана")
}

Scope в коде — это всегда объект-контейнер с CoroutineContext, который:

  • Создаётся явно через конструктор CoroutineScope() или фабричные методы
  • Неявно предоставляется архитектурными компонентами (viewModelScope, lifecycleScope)
  • Управляет отменой через свой Job в контексте
  • Может быть расширен дополнительными элементами контекста (диспетчеры, обработчики ошибок, имена)

Это делает Scope материальным строительным блоком, а не просто концепцией, позволяя чётко контролировать время жизни асинхронных операций в приложении.

Как Scope выглядит в коде | PrepBro