> Как управлять жизненным циклом корутины в Kotlin (Kotlin, Android)
Уровень: senior · Роль: mobile · Категория: Технические вопросы
Компании: IBS
Стек: Kotlin, Android
> Пример ответа
Короткий ответ
Жизненный цикл корутины управляется через Job и CoroutineScope. Основные инструменты: отмена через cancel(), отслеживание состояния через isActive, ensureActive() и CoroutineExceptionHandler. На Android жизненный цикл привязывается к ViewModel через viewModelScope или к LifecycleOwner через lifecycleScope. Ключевой принцип - корутина должна быть отменена, когда её результат больше не нужен, чтобы избежать утечек памяти и лишней работы.
Подробное объяснение
Корутина в Kotlin - это легковесная единица конкурентности, которая выполняется в рамках CoroutineScope. Жизненный цикл корутины состоит из состояний: New, Active, Completing, Completed, Cancelling, Cancelled. Управление происходит через Job - дескриптор корутины, который возвращается при запуске.
Основные методы управления:
job.cancel()- запрашивает отмену. Корутина получитCancellationExceptionв ближайшей точке приостановки.job.cancel(cause)- отмена с указанием причины.job.join()- ожидает завершения корутины.job.cancelAndJoin()- отменяет и ожидает завершения.
Важно понимать: отмена - это кооперативный процесс. Корутина должна проверять состояние отмены. Это делается через:
isActive- свойствоCoroutineScopeилиJob.ensureActive()- бросаетCancellationException, если корутина отменена.yield()- приостанавливает выполнение и проверяет отмену.
Структурированная конкурентность гарантирует, что дочерние корутины автоматически отменяются при отмене родительской. Это ключевой механизм управления жизненным циклом.
На Android используются предопределённые скоупы:
viewModelScope- отменяется при очисткеViewModel.lifecycleScope- привязан кLifecycleOwner, отменяется при уничтожении.repeatOnLifecycle- для реактивных потоков в UI.
На практике
При работе с Android важно привязывать корутины к правильному скоупу. Для UI-операций используйте lifecycleScope с repeatOnLifecycle(Lifecycle.State.STARTED). Для бизнес-логики - viewModelScope. Не создавайте собственные скоупы без необходимости - это частая причина утечек.
При отмене корутины, которая выполняет блокирующие операции (например, чтение из БД), нужно убедиться, что операция прерываемая. Для этого используйте withContext(Dispatchers.IO) и проверяйте isActive внутри циклов.
Обработка ошибок: CoroutineExceptionHandler перехватывает исключения, которые не были обработаны внутри корутины. Для viewModelScope исключения по умолчанию приводят к краху приложения, поэтому всегда обрабатывайте ошибки внутри корутины через try-catch или runCatching.
Пример кода
class MyViewModel : ViewModel() { fun loadData() { viewModelScope.launch { try { val result = fetchData() _uiState.value = UiState.Success(result) } catch (e: CancellationException) { throw e // обязательно пробрасываем, чтобы не сломать отмену } catch (e: Exception) { _uiState.value = UiState.Error(e) } } } } // Отмена с проверкой внутри цикла fun processLargeList(items: List<Int>) { viewModelScope.launch { for (item in items) { ensureActive() // бросает CancellationException при отмене processItem(item) } } } // Привязка к lifecycle class MyFragment : Fragment() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) { viewModel.uiState.collect { state -> render(state) } } } } }
Как отвечать на собеседовании
Начните с определения Job и CoroutineScope, затем объясните кооперативную природу отмены. Подчеркните важность структурированной конкурентности. Приведите пример из Android с viewModelScope. Обязательно упомяните CancellationException и почему его нельзя проглатывать. Если спросят про сложные сценарии - расскажите про SupervisorJob, NonCancellable и withTimeout.
Что проверяет интервьюер
Интервьюер оценивает:
- Понимаете ли вы разницу между
cancel()иjoin(). - Знаете ли вы, что отмена кооперативная и как это работает.
- Умеете ли вы обрабатывать отмену в реальном коде.
- Понимаете ли вы, как скоупы связаны с жизненным циклом Android.
- Знаете ли вы про
CancellationExceptionи его роль.
Типичные ошибки
- Проглатывание
CancellationExceptionвcatch- ломает отмену. - Создание собственного
CoroutineScopeвActivityбез отмены вonDestroy. - Использование
GlobalScope- антипаттерн. - Запуск корутин в
Dispatchers.Mainдля тяжёлых операций. - Игнорирование
ensureActive()в длительных циклах. - Ожидание, что
cancel()мгновенно остановит выполнение - это не так.
> Похожие задачи по mobile
Какой поток используется по умолчанию для вычислений в Kotlin Coroutines?
Что такое оператор to в Kotlin и как он используется
Какой диспетчер использовать для загрузки ресурса с сети в Kotlin корутинах
Как работает компиляция в Kotlin Multiplatform
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью