launch — un Coroutine Builder in Kotlin che avvia una coroutine senza restituire un risultato, restituendo un oggetto Job per controllare l'esecuzione. Questo builder implementa il pattern fire-and-forget: la coroutine inizia a lavorare in un thread in background e termina automaticamente. Secondo la documentazione JetBrains, 2024, launch è il modo principale per eseguire attività parallele in Kotlin Coroutines.
Punti chiave
launch è una funzione di estensione di Kotlin, disponibile tramite l'import kotlinx.coroutines, che crea una nuova coroutine in un determinato CoroutineScope. A differenza delle funzioni normali, il codice all'interno di launch viene eseguito concurrentemente — la coroutine può sospendersi senza bloccare un thread e riprendere più tardi.
Il builder launch è un blocco fondamentale del modello di coroutine di Kotlin. Non restituisce un valore calcolato ma restituisce un oggetto Job che consente di controllare l'esecuzione della coroutine. Tutte le coroutine figlie avviate tramite launch all'interno di un'altra coroutine sono legate alla coroutine padre.
Il builder launch è definito come una funzione inline con diversi parametri: CoroutineScope, CoroutineContext, CoroutineStart e un blocco suspend. I parametri hanno valori predefiniti, rendendo launch comodo per scenari tipici.
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
Il parametro context accetta un CoroutineContext che combina un dispatcher, un gestore di eccezioni e un elemento nominato. Il più delle volte vengono passati Dispatchers.IO, Dispatchers.Main o SupervisorJob per isolare gli errori.
Job — l'oggetto restituito che rappresenta il ciclo di vita della coroutine. Un Job può trovarsi negli stati: New, Active, Completing, Completed, Cancelling, Cancelled. Ogni stato riflette lo stato di esecuzione e consente di reagire ai cambiamenti.
val job = CoroutineScope(Dispatchers.IO).launch {
repeat(10) { i ->
delay(1000L)
println("Avanzamento: $i")
}
}
println("Job è attivo: ${job.isActive}")
delay(2500L)
job.cancel()
println("Job è cancellato: ${job.isCancelled}")
Job supporta una gerarchia: se una coroutine padre viene cancellata, tutte le coroutine figlie vengono automaticamente cancellate. SupervisorJob modifica questo comportamento — le coroutine figlie non vengono cancellate quando una di esse fallisce.
La concorrenza strutturata significa che ogni coroutine viene avviata all'interno di un CoroutineScope specifico e lo scope non viene completato fino a quando tutte le coroutine figlie non terminano il loro lavoro. launch supporta pienamente questo principio — le coroutine avviate all'interno di un'altra coroutine sono sue figlie.
Con chiamate launch annidate, si forma un albero di coroutine. La coroutine padre attende il completamento di tutte le figlie, garantendo un ordine di esecuzione prevedibile e semplificando la gestione delle risorse.
fun main() = runBlocking {
launch {
launch {
delay(1000L)
println("Figlio 1 completato")
}
launch {
delay(500L)
println("Figlio 2 completato")
}
println("Tutti i figli completano prima di questa riga")
}
}
Questo comportamento differisce dalla concorrenza basata su thread, dove i thread figli non sono legati al thread padre. Nelle coroutine, il padre non viene completato fino a quando tutte le figlie non terminano il loro lavoro.
La gestione delle eccezioni in launch dipende dal tipo di Job. Per un Job normale, le eccezioni si propagano alla coroutine padre e la cancellano. Per SupervisorJob o SupervisorScope, le eccezioni sono isolate — un errore in una coroutine figlia non influisce sulle altre.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try {
riskyOperation()
} catch (e: Exception) {
println("Catturato: ${e.message}")
}
}
scope.launch {
println("Questo funziona ancora grazie a SupervisorJob")
}
Per la gestione globale delle eccezioni non catturate, viene utilizzato CoroutineExceptionHandler. Cattura le eccezioni che non sono state gestite all'interno della coroutine e consente di registrare l'errore senza bloccare l'applicazione.
In Android, launch viene utilizzato ovunque: da ViewModel a WorkManager. Il pattern principale è l'uso di lifecycleScope in Fragment e viewModelScope in ViewModel per la cancellazione automatica delle coroutine al termine del ciclo di vita del componente.
class ProfileViewModel : ViewModel() {
private val repository = UserRepository()
fun loadProfile(userId: String) {
viewModelScope.launch(Dispatchers.IO) {
val profile = repository.fetchProfile(userId)
withContext(Dispatchers.Main) {
_profileState.update { it.copy(profile = profile) }
}
}
}
}
viewModelScope cancella automaticamente le coroutine quando il ViewModel viene distrutto. Questo elimina le perdite di memoria e garantisce che le operazioni in background non continuino dopo la perdita del contesto. Inoltre, withContext può essere utilizzato per passare da un dispatcher all'altro.
Domande frequenti
launch restituisce un Job e non restituisce un risultato, mentre async restituisce Deferred<T> per ottenere il risultato. launch viene utilizzato per operazioni fire-and-forget, async — quando è necessario attendere e utilizzare il valore restituito.
Chiama job.cancel() sull'oggetto Job salvato. Per la cancellazione di gruppo, cancella l'intero CoroutineScope tramite scope.cancel(). La coroutine deve essere cooperativa — verificare isActive o utilizzare funzioni suspend cancellabili.
Usa try-catch all'interno del blocco launch o passa CoroutineExceptionHandler in CoroutineContext. Per isolare gli errori, usa SupervisorJob — allora un'eccezione in una coroutine figlia non cancellerà le altre.
No, launch è una funzione di estensione di CoroutineScope. Senza uno scope, la coroutine non può seguire il principio della concorrenza strutturata. Usa GlobalScope.launch con cautela — crea una coroutine senza legame con il ciclo di vita.
Il numero è limitato dal pool di thread del dispatcher. Dispatchers.Default utilizza un numero di thread pari al numero di core CPU. Dispatchers.IO supporta fino a 64 thread. Se vengono avviate più coroutine, vengono messe in coda.
Riepilogo
Svilupperemo un'applicazione mobile chiavi in mano
IT Sectr crea applicazioni iOS e Android per startup e aziende dal 2017. Ti consulteremo e ti proporremo la soluzione migliore.
Leggi anche