catch i onCompletion: obsługa błędów w Flow
Przechwytuj wyjątki z upstreamu i reaguj na zdarzenia zakończenia przepływu.
catch i onCompletion: obsługa błędów w Flow to bezpłatna lekcja Kotlin Academy na CoddyKit. To lekcja 2 z 4. Możesz przeczytać całą lekcję poniżej za darmo — a potem ćwiczyć ją interaktywnie w przeglądarce z wbudowanym edytorem kodu i tutorem AI dostępnym 24/7. To część ścieżki edukacyjnej Kotlin Academy, a Twój postęp synchronizuje się między webem a aplikacją CoddyKit. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Podstawy wyjątków w Flow
Wyjątki w strumieniu Flow kończą jego działanie. Bez obsługi wyjątek propaguje się do odbiorcy, a strumień zostaje zakończony.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw RuntimeException("stream error")
emit(2)
}.collect { println(it) }
} catch (e: Exception) {
println("Caught: ${e.message}")
}
}Operator catch
catch obsługuje wyjątki z nadrzędnego strumienia i może emitować wartości zastępcze albo ponownie zgłosić wyjątek. Nie przechwytuje wyjątków zgłoszonych przez samego odbiorcę.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit(1)
throw RuntimeException("oops")
}.catch { e ->
println("Caught: ${e.message}")
emit(-1) // fallback value
}.collect { println(it) } // 1, then -1
}catch obsługuje tylko nadrzędny strumień
catch przechwytuje wyłącznie wyjątki z konstruktora strumienia Flow i operatorów nadrzędnych — nie wyjątki z lambdy collect.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flowOf(1, 2, 3)
.catch { e -> println("upstream: ${e.message}") }
.collect {
if (it == 2) throw RuntimeException("collector error") // not caught by catch
println(it)
}
} catch (e: Exception) {
println("Collector exception: ${e.message}")
}
}Ponowne zgłaszanie wyjątków w catch
Możesz przeanalizować wyjątek i wybiórczo ponownie zgłosić te wyjątki, których nie możesz obsłużyć.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw IllegalStateException("state error")
}.catch { e ->
if (e is RuntimeException) { emit(-1); return@catch }
throw e // rethrow unknown exceptions
}.collect { println(it) }
} catch (e: Exception) {
println("Rethrown: ${e.message}")
}
}Operator onCompletion
onCompletion wykonuje się po zakończeniu strumienia Flow — normalnym lub spowodowanym wyjątkiem. Jego parametr cause ma wartość inną niż null w przypadku błędu.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf(1, 2, 3)
.onCompletion { cause ->
if (cause == null) println("Completed normally")
else println("Failed: ${cause.message}")
}
.collect { println(it) }
}onCompletion w przypadku błędu
onCompletion wykonuje się nawet wtedy, gdy wystąpi wyjątek w nadrzędnym strumieniu. Otrzymuje wyjątek jako cause, ale go nie wycisza — wyjątek nadal się propaguje.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
try {
flow {
emit(1)
throw RuntimeException("error")
}.onCompletion { cause ->
println("onCompletion cause=${cause?.message}")
}.collect { println(it) }
} catch (e: Exception) {
println("outer catch: ${e.message}")
}
}Łączenie catch i onCompletion
Użyj catch, aby obsłużyć błąd i wyemitować wartości zastępcze, a następnie onCompletion, aby niezależnie od wyniku zarejestrować zdarzenie lub zwolnić zasoby.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flow {
emit("ok")
throw RuntimeException("network error")
}.catch { e ->
emit("fallback") // recover
}.onCompletion {
println("Stream done — release resources")
}.collect { println(it) }
}Operator retry
retry(n) { ... } ponownie subskrybuje nadrzędny strumień po wystąpieniu wyjątku, maksymalnie n razy.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
var attempt = 0
fun unstableFlow() = flow {
attempt++
if (attempt < 3) throw RuntimeException("attempt $attempt failed")
emit("success on attempt $attempt")
}
fun main() = runBlocking {
unstableFlow()
.retry(3) { e -> println("retrying: ${e.message}"); true }
.collect { println(it) }
}retryWhen dla niestandardowej logiki
retryWhen udostępnia wyjątek i liczbę prób, dzięki czemu możesz dodać opóźnienie między próbami lub określić, które wyjątki powodują ponowienie.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
var n = 0
flow {
if (n++ < 2) throw IOException("IO error")
emit("done")
}.retryWhen { cause, attempt ->
cause is IOException && attempt < 3
}.collect { println(it) }
}Operator onStart
onStart wykonuje się przed pierwszą emisją — przydaje się do wyświetlania stanu ładowania lub inicjowania zasobów przed nadejściem danych.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
fun main() = runBlocking {
flowOf("data")
.onStart { emit("Loading...") }
.onCompletion { emit("Done") }
.collect { println(it) }
}Obsługa błędów w rzeczywistych wywołaniach API
Opakuj przepływy repozytorium za pomocą catch, aby mapować wyjątki na błędy domenowe, oraz onCompletion, aby ukrywać wskaźniki ładowania.
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.*
sealed class State { object Loading : State(); data class Data(val v: String) : State(); data class Error(val msg: String) : State() }
fun apiFlow(): Flow<String> = flow { delay(50); emit("response") }
fun uiFlow(): Flow<State> = apiFlow()
.map { State.Data(it) as State }
.onStart { emit(State.Loading) }
.catch { e -> emit(State.Error(e.message ?: "unknown")) }
fun main() = runBlocking { uiFlow().collect { println(it) } }Szybkie sprawdzenie
Jakie jest główne ograniczenie operatora catch?
Podsumowanie
catch obsługuje wyjątki z przepływu źródłowego i może emitować wartości zastępcze. onCompletion wykonuje się zawsze (po pomyślnym zakończeniu lub błędzie) w celu sprzątania albo rejestrowania zdarzeń. Należy łączyć je z retry/retryWhen, aby tworzyć odporne potoki przepływów.
Ucz się Kotlin dzięki korepetycjom AI — za darmo
Pisz i uruchamiaj kod w przeglądarce, otrzymuj natychmiastową pomoc od korepetytora AI dostępnego 24/7 i kontynuuj naukę w sieci lub w aplikacji.
- Kursy
- 51
- Lekcje
- 203
Często zadawane pytania
Czy lekcja „catch i onCompletion: obsługa błędów w Flow” jest bezpłatna?
Tak — pełny tekst „catch i onCompletion: obsługa błędów w Flow” jest dostępny za darmo tutaj w sieci. Aby ćwiczyć ją interaktywnie (wbudowany edytor kodu i tutor AI dostępny 24/7) i odblokować resztę kursu Kotlin Academy, przejdź na CoddyKit PRO. Kurs Kotlin Academy zawiera 4 lekcji w sumie.
Co nauczysz się w „catch i onCompletion: obsługa błędów w Flow”?
Przechwytuj wyjątki z upstreamu i reaguj na zdarzenia zakończenia przepływu. Ćwiczysz Kotlin Academy z praktycznym kodem, który uruchamiasz bezpośrednio w przeglądarce, a tutor AI dostępny 24/7 odpowiada na Twoje pytania podczas pracy nad lekcją.
Czy potrzebuję doświadczenia, aby zacząć Kotlin Academy?
Nie wymagamy żadnego doświadczenia. Kotlin Academy w CoddyKit jest strukturyzowany dla początkujących i zaawansowanych użytkowników, więc możesz zacząć tutaj lub od początku i uczyć się w swoim tempie. To lekcja 2 z 4.
Ile czasu zajmuje lekcja „catch i onCompletion: obsługa błędów w Flow”?
Większość lekcji CoddyKit trwa około 5–10 minut. Każda lekcja to mały, interaktywny krok, dzięki czemu robisz systematyczne postępy i zawsze wracasz dokładnie do tego samego miejsca — na webie i w aplikacji.
Czy mogę pisać i uruchamiać kod w tej lekcji Kotlin Academy?
Tak. Każda lekcja Kotlin Academy zawiera wbudowany edytor kodu, więc piszesz i uruchamiasz prawdziwy kod bezpośrednio w przeglądarce i od razu otrzymujesz sprzężenie zwrotne od AI — bez konfiguracji na komputerze.
Wszystkie lekcje w tym kursie
- Operatory Flow: map, filter, transform i take
- catch i onCompletion: obsługa błędów w Flow
- combine i zip: łączenie wielu Flow
- flowOn i buffer: kontekst i backpressure