0Pricing
Kotlin Academy · Lezione

SupervisorJob e Job: isolamento degli errori

Utilizzi SupervisorJob per impedire che l'errore di una coroutine figlia annulli le coroutine sorelle.

SupervisorJob e Job: isolamento degli errori è una lezione Kotlin Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento Kotlin Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso Kotlin Academy include 4 lezioni in totale.

Propagazione predefinita degli errori dei Job

Con un Job normale, l'errore di un figlio annulla il padre, che a sua volta annulla tutti i fratelli. Un solo errore abbatte l'intera gerarchia.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        coroutineScope {
            launch { delay(50); throw RuntimeException("child 1 failed") }
            launch { delay(1000); println("child 2 — never prints") }
        }
    } catch (e: RuntimeException) {
        println("Caught: ${e.message}")
    }
}

Panoramica di SupervisorJob

SupervisorJob modifica questa regola: l'errore di un figlio NON annulla i fratelli né il padre. Ogni figlio fallisce in modo indipendente.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val supervisor = SupervisorJob()
    val scope = CoroutineScope(coroutineContext + supervisor)
    scope.launch { throw RuntimeException("child 1 failed") }
    scope.launch { delay(100); println("child 2 still runs") }
    delay(200)
    supervisor.cancel()
}

Builder supervisorScope

supervisorScope { } crea uno scope con un SupervisorJob come padre. È il modo idiomatico per eseguire figli indipendenti.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val job1 = launch {
            throw RuntimeException("job1 failed")
        }
        val job2 = launch {
            delay(100)
            println("job2 succeeded")
        }
        job1.join()  // wait for job1 (it failed)
        job2.join()  // job2 is unaffected
    }
}

Gestione degli errori dei figli

Con supervisorScope, ogni figlio gestisce la propria eccezione. Le eccezioni non gestite nei figli devono essere intercettate per ogni singolo figlio.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        val result = async {
            delay(50)
            throw RuntimeException("async failed")
        }
        try {
            result.await()
        } catch (e: RuntimeException) {
            println("Caught from async: ${e.message}")
        }
        println("Scope continues")
    }
}

Job vs SupervisorJob alla creazione dello scope

Passi SupervisorJob() quando crea un CoroutineScope per un servizio o un ViewModel che deve sopravvivere agli errori dei singoli figli.

import kotlinx.coroutines.*
class MyService {
    private val scope = CoroutineScope(Dispatchers.Default + SupervisorJob())
    fun startTask(name: String) {
        scope.launch {
            if (name == "fail") throw RuntimeException("$name failed")
            println("$name done")
        }
    }
    fun stop() = scope.cancel()
}
fun main() = runBlocking {
    val svc = MyService()
    svc.startTask("fail")
    svc.startTask("ok")
    delay(100)
    svc.stop()
}

viewModelScope utilizza SupervisorJob

Il viewModelScope di Android utilizza un SupervisorJob. Un launch che fallisce non annulla le altre coroutine del ViewModel.

import kotlinx.coroutines.*
// Android ViewModel internals:
// val viewModelScope = CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate)
// Each launch is independent — one failure doesn't crash the ViewModel
fun main() = runBlocking {
    println("viewModelScope = SupervisorJob + Main")
}

Decomposizione parallela con supervisorScope

Utilizzi supervisorScope + async per attività parallele in cui alcuni errori non devono influire sulle altre.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val results = supervisorScope {
        val a = async { delay(50); "result-A" }
        val b = async { throw RuntimeException("B failed") }
        val c = async { delay(30); "result-C" }
        listOf(
            runCatching { a.await() },
            runCatching { b.await() },
            runCatching { c.await() }
        )
    }
    results.forEach { println(it) }
}

Quando usare un Job normale

Utilizzi un Job normale (coroutineScope) quando tutti i figli devono completarsi con successo insieme: un errore deve interrompere il gruppo. Come in una transazione: tutto o niente.

import kotlinx.coroutines.*
fun main() = runBlocking {
    try {
        coroutineScope {  // regular Job
            val a = async { delay(50); "A" }
            val b = async { throw RuntimeException("B failed") }
            println(a.await())
            println(b.await())  // throws — cancels a too
        }
    } catch (e: RuntimeException) {
        println("Transaction failed: ${e.message}")
    }
}

Propagazione delle eccezioni in supervisorScope

In supervisorScope, un'eccezione risale allo scope solo se fuoriesce dal livello superiore della coroutine figlia, cioè se nella figlia non è presente alcun try-catch. Lo scope padre non la vede.

import kotlinx.coroutines.*
fun main() = runBlocking {
    supervisorScope {
        // Exception caught inside child — scope unaffected
        launch {
            try { throw RuntimeException("handled") }
            catch (e: Exception) { println("Child caught: ${e.message}") }
        }
        delay(100)
        println("Scope survived")
    }
}

CoroutineExceptionHandler con SupervisorJob

Installi un CoroutineExceptionHandler in uno scope supervisor per registrare o gestire gli errori non catturati dei figli senza causare l'arresto dello scope.

import kotlinx.coroutines.*
fun main() = runBlocking {
    val handler = CoroutineExceptionHandler { _, e ->
        println("Uncaught: ${e.message}")
    }
    val scope = CoroutineScope(SupervisorJob() + handler)
    scope.launch { throw RuntimeException("unhandled failure") }
    scope.launch { delay(100); println("still running") }
    delay(200)
    scope.cancel()
}

Riepilogo dell'isolamento dagli errori

Job: un figlio fallisce → tutti falliscono. SupervisorJob: i figli falliscono indipendentemente. Utilizzi supervisor per i servizi e i ViewModel; utilizzi un Job normale per i gruppi transazionali.

import kotlinx.coroutines.*
// Decision table:
// coroutineScope { }   -> Job: all-or-nothing
// supervisorScope { }  -> SupervisorJob: independent failures
// CoroutineScope(SupervisorJob()) -> long-lived service
fun main() = runBlocking { println("Pick the right job for the right scope") }

Verifica rapida

Quale scope impedisce che l'errore di un figlio annulli i suoi fratelli?

Riepilogo

Job: l'errore si propaga ai fratelli. SupervisorJob/supervisorScope: gli errori sono isolati per ogni figlio. Utilizzi supervisorScope per attività parallele indipendenti e coroutineScope normale per i gruppi transazionali.

Domande Frequenti

La lezione «SupervisorJob e Job: isolamento degli errori» è gratuita?

Sì — il testo completo di «SupervisorJob e Job: isolamento degli errori» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso Kotlin Academy, passa a CoddyKit PRO. Il corso Kotlin Academy include 4 lezioni in totale.

Cosa imparerò in «SupervisorJob e Job: isolamento degli errori»?

Utilizzi SupervisorJob per impedire che l'errore di una coroutine figlia annulli le coroutine sorelle. Eserciti Kotlin Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare Kotlin Academy?

Non è richiesta alcuna esperienza precedente. Kotlin Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «SupervisorJob e Job: isolamento degli errori»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione Kotlin Academy?

Sì. Ogni lezione Kotlin Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. SupervisorJob e Job: isolamento degli errori
  2. CoroutineExceptionHandler: gestore globale delle eccezioni non catturate
  3. Propagazione delle eccezioni con async/await
  4. Progettare architetture resilienti per le coroutine
← Torna a Kotlin Academy