Middle
Come configurare e usare le coroutine nei progetti Kotlin?
sobes.tech AI
Risposta dell'AI
Per configurare le coroutine, è necessario aggiungere la dipendenza corrispondente nel file build.gradle.
// build.gradle (modulo app)
dependencies {
//... altre dipendenze
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Per JVM, Android, JS, Native
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Per Android (se necessario Dispatchers.Main)
}
L'uso delle coroutine include:
-
Scope: Definire l'ambito in cui le coroutine verranno eseguite e gestire il loro ciclo di vita.
GlobalScope: Ambito di tutta l'applicazione, usare con cautela, poiché può causare perdite di memoria.CoroutineScope: Creato esplicitamente, permette di controllare l'annullamento delle coroutine.- Ambiti predefiniti nei framework (ad esempio,
lifecycleScopein Android ViewModel).
// Esempio con CoroutineScope val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Creazione di uno Scope con Dispatcher e Job fun performBackgroundTask() { myScope.launch { // Avvia una coroutine // Processo di calcolo lungo } } fun cancelAllTasks() { myScope.cancel() // Annulla tutte le coroutine nello Scope } -
Builder: Funzioni per avviare coroutine.
launch: Avvia una coroutine che non restituisce risultato esplicito (Job).async: Avvia una coroutine che restituisce risultato sotto forma diDeferred.
import kotlinx.coroutines.* suspend fun fetchData() = coroutineScope { // coroutineScope - builder per la concorrenza strutturata val data1 = async { networkCall1() } // async restituisce un Deferred val data2 = async { networkCall2() } // ... elaborazione dei dati dopo averli ricevuti data1.await() // Ottenere risultato da Deferred, sospende la coroutine fino al completamento data2.await() } suspend fun networkCall1(): String { delay(1000) // Simulazione di richiesta di rete return "Data 1" } suspend fun networkCall2(): String { delay(1500) return "Data 2" } fun startFetching() = runBlocking { // runBlocking - builder per bloccare il thread corrente (per main o test) launch { // launch restituisce un Job println("Fetching data...") fetchData() println("Data fetched!") } } -
Dispatchers: Determinano su quale thread o pool di thread verrà eseguita la coroutine.
Dispatchers.Default: Per compiti intensivi in CPU.Dispatchers.IO: Per operazioni di I/O bloccanti (file, rete).Dispatchers.Main: Thread principale (solo per Android e Swing/JavaFX).Dispatchers.Unconfined: Avvia la coroutine nel thread chiamante, si sospende e poi si riprende nel thread che la ha ripresa.
import kotlinx.coroutines.* fun simpleTask() { GlobalScope.launch(Dispatchers.IO) { // Specificare il dispatcher // Eseguire operazione di I/O println("Esecuzione sul thread: ${Thread.currentThread().name}") } } fun main() = runBlocking { launch(Dispatchers.Default) { println("Thread di default: ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Thread non confinato 1: ${Thread.currentThread().name}") delay(100) // Sospensione println("Thread non confinato 2: ${Thread.currentThread().name}") // Ripresa in altro thread (possibilmente) } delay(200) // Attendere il completamento delle coroutine } -
Funzioni di sospensione: Funzioni contrassegnate con
suspend, che possono essere sospese e riprese senza bloccare il thread. Possono essere chiamate solo da altre funzioni di sospensione o blocchi di coroutine. -
Gestione di cancellazione ed eccezioni: Le coroutine supportano cancellazione strutturata e propagazione delle eccezioni.
- Cancellazione:
import kotlinx.coroutines.* fun cancellableTask() = GlobalScope.launch { try { repeat(1000) { i -> println("Lavorando $i ...") delay(100) // funzione di sospensione che rispetta la cancellazione } } catch (e: CancellationException) { println("Tarefa cancellata!") } finally { println("Pulizia...") } } fun main() = runBlocking { val job = cancellableTask() delay(500) // Attendere un po' job.cancelAndJoin() // Annulla e aspetta la fine } - Eccezioni: In caso di
launch, un'eccezione non catturata causerà il crash dell'applicazione (su Android, di default). In caso diasync, l'eccezione verrà lanciata al momento della chiamata diawait(). Per un controllo più granulare, si usanoCoroutineExceptionHandleroSupervisorJob.
import kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Eccezione catturata: $exception") } val job = GlobalScope.launch(handler) { // Applicare il gestore throw IllegalStateException("Qualcosa è andato storto") } job.join() // Attendere il completamento } - Cancellazione: