Kotlin Academy · Pelajaran

CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap

Pasang CoroutineExceptionHandler untuk mencatat atau memulihkan diri daripada exception yang tidak dikendalikan.

Pelajaran 2 daripada 412 langkah

CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap ialah pelajaran Kotlin Academy percuma di CoddyKit. Ini ialah pelajaran 2 daripada 4. Sebanyak 3 pelajaran dalam laluan pembelajaran ini boleh dibaca sepenuhnya secara percuma — selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan praktikal dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Pelajaran ini merupakan sebahagian daripada laluan pembelajaran Kotlin Academy, dan kemajuan anda disegerakkan merentas web serta aplikasi CoddyKit. Kursus Kotlin Academy merangkumi sejumlah 4 pelajaran.

Apakah CoroutineExceptionHandler?

CoroutineExceptionHandler ialah elemen konteks yang mengendalikan pengecualian yang tidak ditangkap daripada coroutine yang tidak mempunyai pengendali catch. Ia bertindak sebagai pilihan terakhir.

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)
}

Hanya untuk Coroutine Akar

CoroutineExceptionHandler hanya menangkap pengecualian daripada coroutine akar (yang dilancarkan secara langsung pada skop). Coroutine anak menyebarkan pengecualian kepada induknya, bukannya kepada pengendali.

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() } }
}

Tidak Menyekat Pengecualian

Pengendali dipanggil selepas pengecualian itu pun telah membatalkan coroutine. Ia digunakan untuk pengelogan, pelaporan ranap atau pembersihan — bukan untuk menyambung semula pelaksanaan.

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()
    }
}

Pengendali + SupervisorJob

Gabungan SupervisorJob + CoroutineExceptionHandler ialah corak standard untuk skop yang berumur panjang: anak-anak gagal secara berasingan dan kegagalan yang tidak dikendalikan direkodkan.

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()
}

Pengendali dengan async

Untuk async, pengecualian disimpan dalam Deferred dan dilemparkan pada await(). Pengendali TIDAK dicetuskan untuk async melainkan deferred itu tidak ditunggu.

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()
}

Perbandingan Thread.UncaughtExceptionHandler

Tidak seperti UncaughtExceptionHandler Java, pengendali Kotlin ialah sebahagian daripada konteks coroutine dan hanya terpakai dalam coroutine skop tersebut.

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") }

Corak Pengelogan dengan MDC

Dalam aplikasi pelayan, pengendali boleh mendapatkan maklumat konteks coroutine (seperti ID permintaan) untuk pengelogan berstruktur sebelum meneruskannya kepada rangka kerja pengelogan.

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)
}

Integrasi Pelaporan Ranap

Gunakan pengendali untuk meneruskan pengecualian yang tidak ditangkap kepada perkhidmatan pelaporan ranap seperti Firebase Crashlytics atau 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()
}

Pewarisan Pengendali

Pengendali daripada konteks induk TIDAK diwarisi secara automatik oleh coroutine anak. Pengendali itu mesti berada dalam konteks coroutine akar supaya dapat dicetuskan.

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)
}

Ringkasan Amalan Terbaik

Sentiasa pasang CoroutineExceptionHandler pada skop peringkat aplikasi atau peringkat ciri. Rekodkan setiap pengecualian yang bukan pembatalan. Jangan sekali-kali bergantung padanya untuk aliran kawalan — ia hanya untuk kebolehcerapan.

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()
}

Semakan Pantas

Untuk jenis coroutine manakah CoroutineExceptionHandler TIDAK dicetuskan secara automatik?

Imbas Kembali

CoroutineExceptionHandler ialah pemerhati pilihan terakhir untuk pengecualian yang tidak ditangkap dalam coroutine akar. Gabungkannya dengan SupervisorJob untuk skop yang berumur panjang. Gunakannya untuk pengelogan dan pelaporan ranap — jangan sekali-kali untuk aliran kawalan.

Percuma untuk bermula

Pelajari Kotlin dengan tutor kecerdasan buatan — percuma

Tulis dan jalankan kod sebenar dalam pelayar anda, dapatkan bantuan segera daripada tutor kecerdasan buatan yang tersedia 24/7, dan sambung semula dari tempat anda berhenti di web atau dalam aplikasi.

Kursus
51
Pelajaran
203

Soalan Lazim

Adakah pelajaran “CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap” percuma?

Ya — sebanyak 3 pelajaran dalam laluan pembelajaran Kotlin Academy, termasuk “CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap”, boleh dibaca sepenuhnya secara percuma di web ini. Selepas itu, CoddyKit PRO membuka akses kepada semua pelajaran, serta latihan interaktif dengan penyunting kod terbina dalam dan tutor kecerdasan buatan yang tersedia 24/7. Kursus Kotlin Academy merangkumi sejumlah 4 pelajaran.

Apakah yang akan saya pelajari dalam “CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap”?

Pasang CoroutineExceptionHandler untuk mencatat atau memulihkan diri daripada exception yang tidak dikendalikan. Anda berlatih Kotlin Academy menggunakan kod praktikal yang dijalankan terus dalam pelayar, manakala tutor kecerdasan buatan 24/7 menjawab soalan anda semasa anda mengikuti pelajaran.

Adakah saya memerlukan pengalaman untuk memulakan Kotlin Academy?

Tiada pengalaman terdahulu diperlukan. Pembelajaran Kotlin Academy di CoddyKit disusun untuk pelajar daripada peringkat pemula hingga lanjutan, jadi anda boleh bermula di sini atau dari awal dan belajar mengikut kadar anda sendiri. Ini ialah pelajaran 2 daripada 4.

Berapa lamakah pelajaran “CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap” diambil?

Kebanyakan pelajaran CoddyKit mengambil masa kira-kira 5–10 minit. Setiap pelajaran ringkas dan interaktif, jadi anda boleh membuat kemajuan secara berterusan dan menyambung tepat dari tempat anda berhenti di web atau aplikasi.

Bolehkah saya menulis dan menjalankan kod dalam pelajaran Kotlin Academy ini?

Ya. Setiap pelajaran Kotlin Academy menyertakan penyunting kod terbina dalam, jadi anda boleh menulis dan menjalankan kod sebenar terus dalam pelayar serta menerima maklum balas kecerdasan buatan serta-merta — tanpa memerlukan persediaan setempat.

Semua pelajaran dalam kursus ini

  1. SupervisorJob berbanding Job: Pengasingan Kegagalan
  2. CoroutineExceptionHandler: Pengendali Global Tanpa Tangkap
  3. Penyebaran Exception async/await
  4. Mereka Bentuk Seni Bina Coroutine yang Tahan Ralat
← Kembali ke Kotlin Academy