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

Что возвращается внутри onComplete

1.2 Junior🔥 124 комментариев
#Kotlin основы#Многопоточность и асинхронность

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

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

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

Отличный вопрос, который касается одной из ключевых концепций современных асинхронных API в Android, особенно в Kotlin Coroutines и Google Play Services (Tasks).

Ответ зависит от контекста: о каком конкретно onComplete идет речь. Рассмотрим два основных случая.

1. OnComplete в Kotlin Coroutines (в Flow)

В Kotlin корутинах onComplete как отдельного колбэка нет. Есть оператор onCompletion, который является частью Flow API. Это не возвращаемое значение, а terminal operator или intermediate operator, который позволяет выполнить действие при завершении потока данных (Flow), независимо от того, было оно нормальным или с ошибкой.

Что "возвращается" внутри лямбды onCompletion? В его лямбду передается параметр типа Throwable? (cause).

  • Если cause == null — поток завершился успешно.
  • Если cause != null — поток завершился с ошибкой.

Сам оператор onCompletion возвращает новый Flow, который эмитит те же значения, что и исходный, но выполняет переданное действие по завершении.

fun fetchDataFlow(): Flow<String> = flow {
    emit("Data Chunk 1")
    emit("Data Chunk 2")
    // throw RuntimeException("Network error") // Раскомментировать для ошибки
}

// Использование
viewModelScope.launch {
    fetchDataFlow()
        .onEach { value -> Log.d("Flow", "Received: $value") }
        .onCompletion { cause ->
            // Анализируем параметр cause
            if (cause == null) {
                Log.d("Flow", "Flow completed SUCCESSFULLY")
            } else {
                Log.e("Flow", "Flow completed with ERROR: ${cause.message}")
            }
        }
        .collect() // Запускаем поток
}

Ключевой момент: onCompletion не перехватывает ошибку. Чтобы обработать ошибку и продолжить работу, нужно использовать оператор catch.

2. OnComplete в Google Play Services (Task API)

Это классический колбэк-паттерн, используемый в API Firebase, Google Sign-In, Location Services и др. Task<T> представляет асинхронную операцию с результатом типа T.

Метод addOnCompleteListener регистрирует слушатель, который вызывается, когда задача (Task) завершена — независимо от успеха или провала.

Что "возвращается" внутри лямбды onComplete? В лямбду передается сам объект Task<T>. Чтобы получить результат или ошибку, нужно проанализировать эту задачу внутри колбэка.

// Пример с Firebase Auth
auth.signInWithEmailAndPassword(email, password)
    .addOnCompleteListener { task: Task<AuthResult> -> // task - это параметр
        // 1. Проверяем, успешна ли задача
        if (task.isSuccessful) {
            // 2. Если да, БЕЗОПАСНО извлекаем результат.
            // task.result может выбросить исключение, если задача не успешна!
            val result: AuthResult? = task.result
            val user = result?.user
            Log.d("Auth", "Success: ${user?.email}")
        } else {
            // 3. Если задача не успешна, получаем исключение.
            // task.exception гарантированно не-null при isSuccessful == false
            val exception = task.exception
            Log.e("Auth", "Sign-in failed", exception)
        }
    }

Критически важные методы объекта Task, доступные внутри onComplete:

  • isSuccessful: Boolean — флаг успешного завершения.
  • result: T? — возвращает результат только если задача успешна. Вызов этого метода у неуспешной задачи выбросит RuntimeExecutionException!
  • exception: Exception? — возвращает исключение, если задача не успешна. Для успешной задачи возвращает null.

Сравнительная таблица

КритерийonCompletion (Kotlin Flow)onComplete (Play Services Task)
КонтекстАсинхронный поток данных (Flow)Единая асинхронная задача (Task)
Параметр в лямбдеThrowable? causeОбъект Task<T>
Как узнать об успехеcause == nulltask.isSuccessful
Как получить результатНе предназначен для этого. Результаты — в collect или onEach.task.result (только если isSuccessful == true)
Как получить ошибкуПараметр cause (если не null)task.exception (если isSuccessful == false)
Возвращаемое значение методаНовый Flowthis (сам Task для чейнинга)
СтильДекларативный, реактивныйИмперативный, колбэк-ориентированный

Вывод: Внутри onCompletion для Flow вы получаете исключение-причину завершения (Throwable?), а внутри onComplete для Task — вы получаете саму задачу (Task<T>), которую вы должны вручную проверить на успех (isSuccessful) и безопасно извлечь из неё результат или исключение. Это отражает эволюцию от колбэк-адского подхода к более безопасному и декларативному стилю корутин.

Что возвращается внутри onComplete | PrepBro