Какие знаешь методы проверки завершения корутины?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Методы проверки завершения корутины в Kotlin
В Kotlin Coroutines существует несколько ключевых методов для определения состояния выполнения и проверки завершения корутины. Эти подходы варьируются от низкоуровневых проверок состояния до использования встроенных механизмов отмены и обработки исключений.
Основные подходы к проверке завершения
1. Использование свойства isActive
Свойство isActive доступно внутри корутины через coroutineScope или CoroutineScope и указывает, активна ли корутина.
suspend fun checkWithIsActive() {
coroutineScope {
val job = launch {
repeat(1000) { i ->
if (!isActive) {
println("Корутина была отменена")
return@launch
}
println("Работаем: $i")
delay(100)
}
}
delay(350)
job.cancel()
}
}
2. Проверка состояния Job
Каждая корутина связана с объектом Job, который предоставляет информацию о состоянии выполнения.
suspend fun checkJobState() {
val job = GlobalScope.launch {
delay(1000)
println("Корутина завершена")
}
// Проверка состояния через свойства Job
println("isActive: ${job.isActive}")
println("isCompleted: ${job.isCompleted}")
println("isCancelled: ${job.isCancelled}")
job.join() // Ожидание завершения
println("После join: isCompleted = ${job.isCompleted}")
}
Практические методы проверки
3. Использование функции join()
Метод join() приостанавливает вызывающую корутину до завершения целевой корутины.
suspend fun usingJoin() {
val job = launch {
delay(2000)
println("Длительная операция завершена")
}
println("Ожидаем завершения корутины...")
job.join() // Приостановка здесь до завершения job
println("Корутина завершилась, продолжаем работу")
}
4. Комбинация cancel() и join()
Для гарантированной отмены и ожидания завершения.
suspend fun cancelAndJoin() {
val job = launch {
repeat(1000) { i ->
println("Итерация $i")
delay(500)
}
}
delay(1300)
job.cancel() // Запрос отмены
job.join() // Ожидание фактического завершения
println("Корутина полностью остановлена")
}
5. Обработка исключений через try-catch
Корутины генерируют CancellationException при отмене, что можно использовать для определения завершения.
suspend fun handleCancellation() {
val job = GlobalScope.launch {
try {
delay(3000)
println("Успешное завершение")
} catch (e: CancellationException) {
println("Корутина была отменена: ${e.message}")
} finally {
println("Финальные действия при отмене")
}
}
delay(1500)
job.cancel("Причина отмены")
}
6. Использование withTimeout и withTimeoutOrNull
Встроенные функции для ограничения времени выполнения.
suspend fun usingTimeout() {
// withTimeout бросает TimeoutCancellationException
try {
withTimeout(1300) {
repeat(1000) { i ->
println("Работа: $i")
delay(500)
}
}
} catch (e: TimeoutCancellationException) {
println("Время выполнения истекло")
}
// withTimeoutOrNull возвращает null при таймауте
val result = withTimeoutOrNull(1300) {
delay(1000)
"Результат"
}
println("Результат: $result") // null если не успел
}
7. Callback-обработчики состояния Job
Добавление обработчиков через invokeOnCompletion.
fun usingInvokeOnCompletion() {
val job = GlobalScope.launch {
delay(2000)
println("Работа выполнена")
}
job.invokeOnCompletion { cause ->
when {
cause == null -> println("Корутина завершилась успешно")
cause is CancellationException -> println("Корутина отменена")
else -> println("Корутина завершилась с ошибкой: $cause")
}
}
}
Продвинутые техники
8. Использование SupervisorJob и наблюдение за состоянием
suspend fun monitorCoroutineState() {
val supervisorJob = SupervisorJob()
val scope = CoroutineScope(Dispatchers.IO + supervisorJob)
val jobs = mutableListOf<Job>()
repeat(3) { index ->
val job = scope.launch {
delay((index + 1) * 1000L)
println("Корутина $index завершена")
}
jobs.add(job)
}
// Проверка состояния всех корутин
while (jobs.any { it.isActive }) {
delay(500)
val activeCount = jobs.count { it.isActive }
println("Активных корутин: $activeCount")
}
}
9. Комбинация async/await для результата
Для корутин, которые возвращают результат.
suspend fun usingAsyncAwait() {
val deferred = GlobalScope.async {
delay(1500)
42
}
// isCompleted для Deferred
println("Deferred completed: ${deferred.isCompleted}")
try {
val result = deferred.await() // Приостановка до получения результата
println("Получен результат: $result")
} catch (e: Exception) {
println("Ошибка при выполнении: $e")
}
}
Ключевые рекомендации
- Для простых случаев используйте
join()для ожидания завершения - При необходимости отмены применяйте комбинацию
cancelAndJoin() - Для обработки таймаутов предпочитайте
withTimeoutOrNullкак более безопасный вариант - Для реактивного подхода используйте
invokeOnCompletionдля callback-обработки - Всегда проверяйте
isActiveвнутри длительных циклов в корутинах для корректной реакции на отмену - Помните о структурированной конкурентности — предпочитайте
coroutineScopeвместо глобальных scope для автоматического управления жизненным циклом
Выбор конкретного метода зависит от контекста: нужно ли просто дождаться завершения, обработать отмену, получить результат или ограничить время выполнения. Правильное использование этих методов обеспечивает надежное управление жизненным циклом корутин и предотвращает утечки ресурсов.