Sobes.tech
Middle

Какви методи за обработка на грешки в корутините познавате?

sobes.tech AI

Отговор от AI

  • Използване на try...catch блокове. Стандартен начин за обработка на изключения. Работи вътре в корутината.

    // Използване на try-catch
    suspend fun fetchData(): String {
        return try {
            // Операция, която може да хвърли изключение
            throw Exception("Грешка при зареждане на данни")
            "Данните са успешно заредени"
        } catch (e: Exception) {
            "Грешка: ${e.message}"
        }
    }
    

    try...catch не е подходящ за обработка на непотискани изключения, хвърлени от дъщерни корутини, стартирани в друг CoroutineScope.

  • CoroutineExceptionHandler. Хваща необработени изключения, хвърлени от корутините, които са стартирани в този CoroutineScope или в неговите дъщерни CoroutineScope.

    // CoroutineExceptionHandler
    val handler = CoroutineExceptionHandler { _, exception ->
        println("Хванато изключение: $exception")
    }
    
    // Използване на CoroutineExceptionHandler
    GlobalScope.launch(handler) {
        // Корутината, която може да хвърли изключение
        throw Exception("Грешка в корутината")
    }
    

    CoroutineExceptionHandler се активира само за изключения, които не са обработени от механизма на структурирана конкуренция.

  • SupervisorJob и supervisorScope. За разлика от обикновения Job, когато дъщерна корутина с грешка води до отменяне на родителския Job, SupervisorJob не отменя родителския Job при грешка в дъщерната корутина. supervisorScope създава CoroutineScope с SupervisorJob.

    // Използване на supervisorScope
    suspend fun loadMultipleData() = supervisorScope {
        val data1 = async {
            // Може да хвърли изключение
            throw Exception("Грешка в данни 1")
            "Данни 1"
        }
        val data2 = async {
            "Данни 2"
        }
    
        // Може да обработи изключение за конкретната async
        try {
            println("Резултат 1: ${data1.await()}")
        } catch (e: Exception) {
            println("Грешка при зареждане на данни 1: ${e.message}")
        }
        println("Резултат 2: ${data2.await()}")
    }
    

    Използва се за независими дъщерни задачи, където грешката на една не трябва да влияе на другите. Не заменя try...catch или CoroutineExceptionHandler, а по-скоро променя поведението при разпространение на изключения.

  • Разпространение на изключения в структурирана конкуренция. По подразбиране, изключение в дъщерна корутина отменя родителската корутина и всички нейни сиблинги.

    // Пример за разпространение на изключение
    runBlocking {
        val job = launch {
            launch { // Дъщерна корутина 1
                delay(100)
                throw Exception("Грешка в дъщерната 1")
            }
            launch { // Дъщерна корутина 2
                delay(200)
                println("Дъщерната 2 завърши")
            }
        }
        try {
            job.join()
        } catch (e: Exception) {
            println("Обработено изключение в родителя: $e")
        }
    }
    

    Това е основното поведение на структурирана конкуренция, което помага да се избегнат течове на ресурси и състояния.

  • Използване на async с await(). Изключения, хвърлени в async, не се разпространяват автоматично. Те се съхраняват вътре в Deferred и се хвърлят само при извикване на await().

    // Обработка на изключения с async/await
    suspend fun safeAsyncCall() = coroutineScope {
        val deferred = async {
            throw Exception("Грешка в async")
            "Резултат от async"
        }
    
        try {
            val result = deferred.await()
            println("Резултат: $result")
        } catch (e: Exception) {
            println("Хванато изключение от async: ${e.message}")
        }
    }
    

    Това позволява избирателна обработка на грешки за всяка асинхронна задача.

Начин Назначение Обработва непотискани? Променя разпространението?
try...catch Обработка на изключения вътре в текущата корутина Не Не
CoroutineExceptionHandler Хваща необработени изключения в Scope Да Не
SupervisorJob/Scope Промяна на поведението при разпространение на изключения Не Да
Структурирана конкуренция Автоматично отменяне при грешка Да Да
async + await() Отложено разпространение на изключение Не Да (до await)