Πώς να ρυθμίσετε και να χρησιμοποιήσετε τις coroutine σε έργα Kotlin;
sobes.tech AI
Απάντηση από AI
Για τη ρύθμιση των κορουτινών, πρέπει να προσθέσετε την κατάλληλη εξάρτηση στο αρχείο build.gradle.
// build.gradle (τμήμα εφαρμογής)
dependencies {
//... άλλες εξαρτήσεις
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") // Για JVM, Android, JS, Native
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3") // Για Android (αν χρειάζεται Dispatchers.Main)
}
Η χρήση των κορουτινών περιλαμβάνει:
-
Περιοχή ζωής (Scope): Ορισμός της περιοχής στην οποία θα εκτελούνται οι κορουτίνες και διαχείριση του κύκλου ζωής τους.
GlobalScope: Περιοχή όλης της εφαρμογής, χρησιμοποιήστε με προσοχή, καθώς μπορεί να οδηγήσει σε διαρροές μνήμης.CoroutineScope: Δημιουργείται ρητά, επιτρέπει τον έλεγχο ακύρωσης των κορουτινών.- Προκαθορισμένες περιοχές σε πλαίσια (π.χ.,
lifecycleScopeστο Android ViewModel).
// Παράδειγμα με CoroutineScope val myScope = CoroutineScope(Dispatchers.Default + SupervisorJob()) // Δημιουργία Scope με Dispatcher και Job fun performBackgroundTask() { myScope.launch { // Εκκίνηση κορουτίνας // Μακράς διάρκειας υπολογιστική διαδικασία } } fun cancelAllTasks() { myScope.cancel() // Ακύρωση όλων των κορουτινών στο Scope } -
Κατασκευαστές κορουτινών (Builders): Συναρτήσεις για την εκκίνηση κορουτινών.
launch: Ξεκινά μια κορουτίνα που δεν επιστρέφει αποτέλεσμα ρητά (Job).async: Ξεκινά μια κορουτίνα που επιστρέφει αποτέλεσμα ωςDeferred.
import kotlinx.coroutines.* suspend fun fetchData() = coroutineScope { // coroutineScope - builder για δομημένο ανταγωνισμό val data1 = async { networkCall1() } // async επιστρέφει Deferred val data2 = async { networkCall2() } // ... επεξεργασία δεδομένων μετά την λήψη data1.await() // Λήψη αποτελέσματος από Deferred, θέτει την κορουτίνα σε αναμονή μέχρι να ολοκληρωθεί data2.await() } suspend fun networkCall1(): String { delay(1000) // Προσομοίωση δικτυακού αιτήματος return "Data 1" } suspend fun networkCall2(): String { delay(1500) return "Data 2" } fun startFetching() = runBlocking { // runBlocking - builder για μπλοκάρισμα του τρέχοντος νήματος launch { // launch επιστρέφει Job println("Fetching data...") fetchData() println("Data fetched!") } } -
Dispatchers: Ορίζουν σε ποιο νήμα ή πού θα εκτελεστεί η κορουτίνα.
Dispatchers.Default: Για εργασίες που απαιτούν CPU.Dispatchers.IO: Για μπλοκαριστικές λειτουργίες I/O (αρχεία, δίκτυο).Dispatchers.Main: Κύριο νήμα (μόνο για Android και Swing/JavaFX).Dispatchers.Unconfined: Ξεκινά την κορουτίνα στο καλούν νήμα, κοιμάται και συνεχίζει στο νήμα που την επανεκκινεί.
import kotlinx.coroutines.* fun simpleTask() { GlobalScope.launch(Dispatchers.IO) { // Ορισμός dispatcher // Εκτέλεση λειτουργίας I/O println("Running on thread: ${Thread.currentThread().name}") } } fun main() = runBlocking { launch(Dispatchers.Default) { println("Default thread: ${Thread.currentThread().name}") } launch(Dispatchers.Unconfined) { println("Unconfined thread 1: ${Thread.currentThread().name}") delay(100) // Κοιμάται println("Unconfined thread 2: ${Thread.currentThread().name}") // Επανεκκίνηση σε άλλο νήμα (πιθανώς) } delay(200) // Αναμονή για ολοκλήρωση των κορουτινών } -
Λειτουργίες αναστολής (Suspending functions): Συναρτήσεις με το
suspend, που μπορούν να ανασταλούν και να συνεχιστούν χωρίς να μπλοκάρουν το νήμα. Μπορούν να καλούνται μόνο από άλλες λειτουργίες αναστολής ή από μπλοκ κορουτίνας. -
Διαχείριση ακύρωσης και εξαιρέσεων: Οι κορουτίνες υποστηρίζουν δομημένη ακύρωση και διανομή εξαιρέσεων.
- Ακύρωση:
import kotlinx.coroutines.* fun cancellableTask() = GlobalScope.launch { try { repeat(1000) { i -> println("Working $i ...") delay(100) // λειτουργία suspend που σέβεται την ακύρωση } } catch (e: CancellationException) { println("Task was cancelled!") } finally { println("Cleaning up...") } } fun main() = runBlocking { val job = cancellableTask() delay(500) // Αναμονή job.cancelAndJoin() // Ακύρωση και αναμονή ολοκλήρωσης } - Εξαιρέσεις: Στην περίπτωση
launch, η μη-αντιμετωπιζόμενη εξαίρεση θα οδηγήσει σε πτώση της εφαρμογής (στο Android κατά κανόνα). Στην περίπτωσηasync, η εξαίρεση θα ριχθεί κατά την κλήσηawait(). Για πιο λεπτομερή έλεγχο, χρησιμοποιούνταιCoroutineExceptionHandlerήSupervisorJob.
import kotlinx.coroutines.* fun main() = runBlocking { val handler = CoroutineExceptionHandler { _, exception -> println("Caught exception: $exception") } val job = GlobalScope.launch(handler) { // Εφαρμογή handler throw IllegalStateException("Something went wrong") } job.join() // Αναμονή για ολοκλήρωση } - Ακύρωση: