CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków
Zainstaluj CoroutineExceptionHandler, aby rejestrować nieobsłużone wyjątki lub odzyskiwać po nich działanie.
CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków 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.
Czym jest CoroutineExceptionHandler?
CoroutineExceptionHandler to element kontekstu obsługujący nieprzechwycone wyjątki z korutyn, które nie mają obsługi catch. Działa jako mechanizm ostateczny.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { context, exception ->
println("Caught unhandled: ${exception.message}")
}
fun main() = runBlocking {
val scope = CoroutineScope(Dispatchers.Default + handler)
scope.launch { throw RuntimeException("oops") }
delay(100)
}Tylko dla korutyn głównych
CoroutineExceptionHandler przechwytuje wyjątki tylko z korutyn głównych (uruchomionych bezpośrednio w zakresie). Korutyny potomne propagują wyjątki do korutyny nadrzędnej, a nie do handlera.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
// Root coroutine — handler fires:
CoroutineScope(handler).launch {
throw RuntimeException("root error")
}
delay(100)
// NOT handler (child of coroutineScope):
// launch { launch { throw RuntimeException() } }
}Nie tłumi wyjątku
Handler jest wywoływany po tym, jak wyjątek anulował już korutynę. Służy do rejestrowania, raportowania awarii lub sprzątania — nie do wznawiania wykonywania.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e ->
println("[CrashReport] ${e::class.simpleName}: ${e.message}")
// send to Crashlytics, Sentry, etc.
}
fun main() = runBlocking {
CoroutineScope(SupervisorJob() + handler).apply {
launch { throw IllegalStateException("state error") }
launch { delay(100); println("still alive") }
delay(200)
cancel()
}
}Handler + SupervisorJob
Połączenie SupervisorJob + CoroutineExceptionHandler jest standardowym wzorcem dla długotrwałych zakresów: dzieci kończą się niepowodzeniem niezależnie od siebie, a nieobsłużone błędy są rejestrowane.
import kotlinx.coroutines.*
class AppScope {
private val handler = CoroutineExceptionHandler { _, e ->
println("Uncaught: ${e.message}")
}
val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
}
fun main() = runBlocking {
val app = AppScope()
app.scope.launch { throw RuntimeException("task failed") }
app.scope.launch { delay(100); println("other task ok") }
delay(200)
app.scope.cancel()
}Handler z async
W przypadku async wyjątki są przechowywane w obiekcie Deferred i zgłaszane przy wywołaniu await(). Handler NIE jest uruchamiany dla async, chyba że nie oczekuje się na obiekt deferred.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
val scope = CoroutineScope(SupervisorJob() + handler)
val deferred = scope.async { throw RuntimeException("async error") }
try {
deferred.await() // exception thrown here
} catch (e: RuntimeException) {
println("Caught from await: ${e.message}")
}
delay(50)
scope.cancel()
}Porównanie z Thread.UncaughtExceptionHandler
W przeciwieństwie do mechanizmu UncaughtExceptionHandler w Javie handler Kotlina jest częścią kontekstu korutyny i ma zastosowanie tylko do korutyn działających w tym zakresie.
import kotlinx.coroutines.*
// Java style (applies to threads):
Thread.setDefaultUncaughtExceptionHandler { t, e ->
println("Thread ${t.name} threw: ${e.message}")
}
// Kotlin coroutine style (applies to coroutines in scope):
val handler = CoroutineExceptionHandler { _, e ->
println("Coroutine threw: ${e.message}")
}
fun main() = runBlocking { println("Handlers target different concurrency models") }Wzorzec rejestrowania z MDC
W aplikacjach serwerowych handler może przechwytywać informacje z kontekstu korutyny, takie jak identyfikatory żądań, na potrzeby strukturalnego rejestrowania przed przekazaniem ich do frameworka rejestrowania.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { ctx, e ->
val jobName = ctx[CoroutineName]?.name ?: "unknown"
println("[${jobName}] ERROR: ${e.message}")
}
fun main() = runBlocking {
CoroutineScope(SupervisorJob() + handler).launch(CoroutineName("DataLoader")) {
throw RuntimeException("fetch failed")
}
delay(100)
}Integracja z raportowaniem awarii
Należy używać handlera do przekazywania nieprzechwyconych wyjątków do usług raportowania awarii, takich jak Firebase Crashlytics lub Sentry.
import kotlinx.coroutines.*
object CrashReporter {
fun record(e: Throwable) = println("[Crashlytics] ${e.message}")
}
val handler = CoroutineExceptionHandler { _, e ->
if (e !is CancellationException) CrashReporter.record(e)
}
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + handler)
fun main() = runBlocking {
appScope.launch { throw RuntimeException("unhandled in production") }
delay(100)
appScope.cancel()
}Dziedziczenie handlera
Handler z kontekstu nadrzędnego NIE jest automatycznie dziedziczony przez korutyny potomne. Aby został uruchomiony, musi znajdować się w kontekście korutyny głównej.
import kotlinx.coroutines.*
val handler = CoroutineExceptionHandler { _, e -> println("Handler: ${e.message}") }
fun main() = runBlocking {
// Handler only fires at root level:
CoroutineScope(SupervisorJob() + handler).launch {
// Child of root — exception propagates to root handler:
launch { throw RuntimeException("nested") }
}
delay(100)
}Podsumowanie dobrych praktyk
Należy zawsze instalować CoroutineExceptionHandler w zakresach na poziomie aplikacji lub funkcji. Należy rejestrować każdy wyjątek niezwiązany z anulowaniem. Nigdy nie należy polegać na nim w sterowaniu przepływem — służy wyłącznie do obserwowalności.
import kotlinx.coroutines.*
val globalHandler = CoroutineExceptionHandler { ctx, e ->
if (e !is CancellationException) {
println("[ERROR] ${ctx[CoroutineName]?.name}: ${e.message}")
}
}
val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default + globalHandler)
fun main() = runBlocking {
appScope.launch(CoroutineName("Auth")) { throw RuntimeException("token expired") }
delay(100); appScope.cancel()
}Szybkie sprawdzenie
Dla jakiego typu korutyny CoroutineExceptionHandler NIE jest uruchamiany automatycznie?
Podsumowanie
CoroutineExceptionHandler jest mechanizmem ostatecznym do obserwowania nieprzechwyconych wyjątków w korutynach głównych. Należy łączyć go z SupervisorJob w długotrwałych zakresach. Należy używać go do rejestrowania i raportowania awarii — nigdy do sterowania przepływem.
Często zadawane pytania
Czy lekcja „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków” jest bezpłatna?
Tak — pełny tekst „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków” 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 „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków”?
Zainstaluj CoroutineExceptionHandler, aby rejestrować nieobsłużone wyjątki lub odzyskiwać po nich działanie. Ć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 „CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków”?
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
- SupervisorJob a Job: izolowanie błędów
- CoroutineExceptionHandler: globalny handler nieprzechwyconych wyjątków
- Propagacja wyjątków w async/await
- Projektowanie odpornych architektur korutyn