DANFA

Kotlin: onSuccess и onError

В Kotlin (особенно при работе с корутинами и асинхронными операциями) часто встречаются конструкции onSuccess и onError. Они служат для обработки результатов асинхронных операций — как успешных, так и ошибочных.

Что это такое?


Это лямбда‑функции (callback-обработчики), которые:
  • onSuccess — вызывается при успешном завершении операции;
  • onError — вызывается при возникновении ошибки.

Они позволяют отделить логику обработки результата от самого выполнения операции.

Где применяются


Чаще всего встречаются в:
  • сетевых запросах (Retrofit, Ktor);
  • работе с БД (Room, SQLDelight);
  • корутинах (async, await);
  • RxJava/RxKotlin;
  • библиотеках для работы с файлами/IO.

Базовый синтаксис
someAsyncOperation(
    onSuccess = { result ->
        // Обработка успешного результата
    },
    onError = { exception ->
        // Обработка ошибки
    }
)

Практические примеры



Сетевой запрос (Retrofit)
apiService.getUser(userId)
    .enqueue(object : Callback<User> {
        override fun onResponse(call: Call<User>, response: Response<User>) {
            if (response.isSuccessful) {
                onSuccess(response.body()!!)
            } else {
                onError(HttpException(response))
            }
        }

        override fun onFailure(call: Call<User>, t: Throwable) {
            onError(t)
        }
    })

Корутины с async
scope.launch {
    val deferred = async {
        fetchDataFromNetwork()
    }

    try {
        val result = deferred.await()
        onSuccess(result)
    } catch (e: Exception) {
        onError(e)
    }
}

Пользовательский класс с callback-ами
class DataLoader {
    fun loadData(
        onSuccess: (List<String>) -> Unit,
        onError: (Throwable) -> Unit
    ) {
        scope.launch {
            try {
                val data = fetchFromServer()
                onSuccess(data)
            } catch (e: IOException) {
                onError(e)
            }
        }
    }
}

// Использование:
dataLoader.loadData(
    onSuccess = { data -> 
        println("Данные загружены: $data")
    },
    onError = { error ->
        println("Ошибка: ${error.message}")
    }
)

Лучшие практики



Всегда обрабатывайте ошибки
Даже если просто логируете:
onError = { e -> 
    Log.e("Network", "Ошибка загрузки", e)
}

Используйте типобезопасные ошибки
sealed class NetworkError {
    data class HttpError(val code: Int) : NetworkError()
    object Timeout : NetworkError()
}

onError = { error ->
    when (error) {
        is NetworkError.HttpError -> showHttpError(error.code)
        is NetworkError.Timeout -> showTimeoutMessage()
    }
}

Не оставляйте onError пустым
Пустой onError = {} скрывает проблемы.

Используйте onSuccess для побочных эффектов
onSuccess = { user ->
    saveToCache(user)
    updateUI(user)
    trackAnalytics("user_loaded")
}

Альтернативы


В современном Kotlin часто используют:

Result класс (встроенный в Kotlin 1.5+):
fun fetchData(): Result<Data> { ... }

result.fold(
    onSuccess = { /* ... */ },
    onFailure = { /* ... */ }
)

Sealed классы для типизированных результатов;
Flow/StateFlow для реактивного программирования.

Когда выбирать onSuccess/onError?


Используйте, если:
  • работаете с legacy-кодом;
  • используете библиотеки с callback-интерфейсами;
  • нужна простая обработка без сложных цепочек.

Откажитесь, если:
  • проект использует Flow или StateFlow;
  • нужна сложная композиция операций;
  • требуется обработка нескольких событий.

Вывод


onSuccess и onError — это:
  • простой способ обработки асинхронных результатов;
  • стандартный паттерн в Kotlin;
  • удобный инструмент для разделения логики успеха и ошибок.

Главное — всегда обрабатывать ошибки и не игнорировать возможные сбои.

Автор:  23.02.2026 05:49:27 am