Sobes.tech
Middle

Какво знаете за обработката на грешки във Flow?

sobes.tech AI

Отговор от AI

Flow в Kotlin Coroutines предоставя няколко начина за обработка на грешки:

  1. Оператор catch: Засича изключения във възходящия поток и позволява да се изпълни действие (например логване, връщане на резервни данни) или да се замени потокът.

    flow {
        emit(1)
        throw RuntimeException("Възникна грешка")
    }.catch { e: Throwable ->
        // Обработка на грешката
        emit(-1) // Излъчване на друго стойност при грешка
    }.collect { value ->
        // Обработка на стойностите
    }
    
  2. Блок try-catch: Класически начин за обработка на изключения около част от кода, включително събиране на Flow.

    try {
        flow {
            emit(1)
            throw RuntimeException("Възникна грешка")
        }.collect { value ->
            // Обработка на стойностите
        }
    } catch (e: Throwable) {
        // Обработка на грешката
    }
    

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

  3. Оператор onEach с try-catch: Ако трябва да обработите грешки за всеки елемент поотделно.

    flow {
        emit(1)
        emit(2)
        throw RuntimeException("Грешка след 2")
        emit(3)
    }.onEach { value ->
        try {
            // Обработка на всеки елемент
            if (value == 2) throw IllegalArgumentException("Невалидна стойност 2")
        } catch (e: Throwable) {
            // Обработка на грешката за конкретната стойност
            println("Грешка за стойността $value: ${e.message}")
            // Може да пренасочите изключението, ако искате да спрете потока
            throw e
        }
    }.catch { e: Throwable ->
        // Обработка на грешки, които не са уловени в onEach, или грешки, изхвърлени след onEach
        println("Обща грешка: ${e.message}")
    }.collect { value ->
        println("Събрана стойност: $value")
    }
    
  4. Оператор retry / retryWhen: Позволяват да се повтори източникът на Flow при възникване на грешка.

    • retry: просто повтаря опита зададения брой пъти.
    • retryWhen: позволява да се определи условие за повторение.
    var attempt = 0
    flow {
        println("Опит ${++attempt}")
        if (attempt < 3) throw RuntimeException("Повторен опит")
        emit(10)
    }.retryWhen { cause, attempt ->
        // Логика за определяне дали да се повтори
        cause is RuntimeException && attempt < 3
    }.collect { value ->
        println("Успех: $value")
    }
    
  5. Пробутване на изключения: Грешки, които не са уловени явно, ще бъдат пренасочени нагоре по веригата на Flow и могат да бъдат уловени в блок try-catch около събирача на Flow или с оператора catch.

Важно е да се разбере, че операторът catch засича грешки във възходящия поток (upstream). Грешки, възникващи във низходящия поток (downstream) след catch, не се засичат. За обработка на такива грешки трябва да се използва друг catch по-надолу по веригата или try-catch около събирача.

Общият съвет: поставяйте обработката на грешки възможно най-близо до източника на грешката, ако е възможно, но имайте предвид, че catch обработва само възходящия поток.