launch — Coroutine Builder στην Kotlin που εκκινεί μια coroutine χωρίς να επιστρέφει αποτέλεσμα, επιστρέφοντας ένα αντικείμενο Job για τη διαχείριση της εκτέλεσης. Αυτός ο builder υλοποιεί το μοτίβο fire-and-forget: η coroutine ξεκινά να εργάζεται σε ένα νήμα παρασκηνίου και τερματίζεται αυτόματα. Σύμφωνα με την τεκμηρίωση της JetBrains, 2024, το launch είναι ο κύριος τρόπος εκκίνησης παράλληλων εργασιών στο Kotlin Coroutines.
Κύρια σημεία
launch — είναι μια συνάρτηση επέκτασης της Kotlin, διαθέσιμη μέσω του import kotlinx.coroutines, η οποία δημιουργεί μια νέα coroutine σε ένα καθορισμένο CoroutineScope. Σε αντίθεση με τις συνηθισμένες συναρτήσεις, ο κώδικας εντός του launch εκτελείται ταυτόχρονα — η coroutine μπορεί να ανασταλεί (suspend) χωρίς να μπλοκάρει το νήμα και να συνεχιστεί αργότερα.
Ο builder launch είναι ένα θεμελιώδες δομικό στοιχείο του μοντέλου coroutine της Kotlin. Δεν επιστρέφει μια υπολογισμένη τιμή, αλλά επιστρέφει ένα αντικείμενο Job που επιτρέπει τον έλεγχο της εκτέλεσης της coroutine. Όλες οι θυγατρικές coroutine που εκκινούνται μέσω launch εντός άλλης coroutine συνδέονται με τη γονική.
Ο builder launch ορίζεται ως inline συνάρτηση με πολλές παραμέτρους: CoroutineScope, CoroutineContext, CoroutineStart και suspend-block. Οι παράμετροι έχουν προεπιλεγμένες τιμές, καθιστώντας το launch βολικό για τυπικά σενάρια.
public fun CoroutineScope.launch(
context: CoroutineContext = EmptyCoroutineContext,
start: CoroutineStart = CoroutineStart.DEFAULT,
block: suspend CoroutineScope.() -> Unit
): Job
Η παράμετρος context δέχεται ένα CoroutineContext που συνδυάζει τον dispatcher, τον χειριστή εξαιρέσεων και ένα ονομασμένο στοιχείο. Συχνότερα μεταβιβάζονται Dispatchers.IO, Dispatchers.Main ή SupervisorJob για απομόνωση σφαλμάτων.
Job — το επιστρεφόμενο αντικείμενο που αντιπροσωπεύει τον κύκλο ζωής της coroutine. Το Job μπορεί να βρίσκεται σε καταστάσεις: New, Active, Completing, Completed, Cancelling, Cancelled. Κάθε κατάσταση αντικατοπτρίζει την κατάσταση εκτέλεσης και επιτρέπει την αντίδραση σε αλλαγές.
val job = CoroutineScope(Dispatchers.IO).launch {
repeat(10) { i ->
delay(1000L)
println("Πρόοδος: $i")
}
}
println("Το Job είναι ενεργό: ${job.isActive}")
delay(2500L)
job.cancel()
println("Το Job ακυρώθηκε: ${job.isCancelled}")
Το Job υποστηρίζει ιεραρχία: εάν η γονική coroutine ακυρωθεί, όλες οι θυγατρικές ακυρώνονται αυτόματα. Το SupervisorJob αλλάζει αυτήν τη συμπεριφορά — οι θυγατρικές coroutine δεν ακυρώνονται σε περίπτωση σφάλματος μιας από αυτές.
Δομημένη ταυτοχρονικότητα σημαίνει ότι κάθε coroutine εκκινείται σε ένα συγκεκριμένο CoroutineScope και το scope δεν ολοκληρώνεται έως ότου όλες οι θυγατρικές coroutine ολοκληρώσουν την εργασία τους. Το launch υποστηρίζει πλήρως αυτήν την αρχή — οι coroutine που εκκινούνται εντός άλλης coroutine είναι θυγατρικές της.
Κατά την ένθετη εκκίνηση launch σχηματίζεται ένα δέντρο coroutine. Η γονική coroutine αναμένει την ολοκλήρωση όλων των θυγατρικών, γεγονός που εγγυάται προβλέψιμη σειρά εκτέλεσης και απλοποιεί τη διαχείριση πόρων.
fun main() = runBlocking {
launch {
launch {
delay(1000L)
println("Παιδί 1 ολοκληρώθηκε")
}
launch {
delay(500L)
println("Παιδί 2 ολοκληρώθηκε")
}
println("Όλα τα παιδιά ολοκληρώθηκαν πριν από αυτήν τη γραμμή")
}
}
Αυτή η συμπεριφορά διαφέρει από την ταυτοχρονικότητα που βασίζεται σε νήματα, όπου τα θυγατρικά νήματα δεν συνδέονται με το γονικό. Στις coroutine, το γονικό δεν ολοκληρώνεται έως ότου όλα τα παιδιά ολοκληρώσουν την εργασία τους.
Η διαχείριση εξαιρέσεων στο launch εξαρτάται από τον τύπο Job. Για ένα κανονικό Job, οι εξαιρέσεις διαδίδονται στη γονική coroutine και την ακυρώνουν. Για SupervisorJob ή SupervisorScope, οι εξαιρέσεις απομονώνονται — το σφάλμα μιας θυγατρικής coroutine δεν επηρεάζει τις άλλες.
val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
scope.launch {
try {
riskyOperation()
} catch (e: Exception) {
println("Συλλήφθηκε: ${e.message}")
}
}
scope.launch {
println("Αυτό ακόμα λειτουργεί χάρη στο SupervisorJob")
}
Για καθολική διαχείριση μη συλληφθέντων εξαιρέσεων χρησιμοποιείται το CoroutineExceptionHandler. Αυτό συλλαμβάνει εξαιρέσεις που δεν έχουν διαχειριστεί εντός της coroutine και επιτρέπει την καταγραφή του σφάλματος χωρίς κατάρρευση της εφαρμογής.
Στο Android, το launch εφαρμόζεται παντού: από ViewModel έως WorkManager. Το κύριο μοτίβο είναι η χρήση lifecycleScope στο Fragment και viewModelScope στο ViewModel για αυτόματη ακύρωση coroutine κατά το τέλος του κύκλου ζωής του component.
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 ακυρώνει αυτόματα τις coroutine κατά την καταστροφή του ViewModel. Αυτό εξαλείφει διαρροές μνήμης και εγγυάται ότι οι λειτουργίες παρασκηνίου δεν συνεχίζονται μετά την απώλεια περιβάλλοντος. Επιπλέον, μπορεί να χρησιμοποιηθεί withContext για εναλλαγή μεταξύ dispatcher.
Συχνές Ερωτήσεις
launch επιστρέφει Job και δεν επιστρέφει αποτέλεσμα εκτέλεσης, ενώ το async επιστρέφει Deferred<T> για λήψη αποτελέσματος. Το launch χρησιμοποιείται για λειτουργίες fire-and-forget, το async — όταν πρέπει να περιμένετε και να χρησιμοποιήσετε την επιστρεφόμενη τιμή.
Καλέστε job.cancel() στο αποθηκευμένο αντικείμενο Job. Για ομαδική ακύρωση, ακυρώστε ολόκληρο το CoroutineScope μέσω scope.cancel(). Η coroutine πρέπει να είναι συνεργατική — να ελέγχει το isActive ή να χρησιμοποιεί επαληθεύσιμες suspend συναρτήσεις.
Χρησιμοποιήστε try-catch εντός του μπλοκ launch ή μεταβιβάστε CoroutineExceptionHandler στο CoroutineContext. Για απομόνωση σφαλμάτων χρησιμοποιήστε SupervisorJob — τότε η εξαίρεση σε μια θυγατρική coroutine δεν θα ακυρώσει τις υπόλοιπες.
Όχι, το launch είναι συνάρτηση επέκτασης του CoroutineScope. Χωρίς scope, η coroutine δεν μπορεί να ακολουθήσει την αρχή της δομημένης ταυτοχρονικότητας. Χρησιμοποιήστε το GlobalScope.launch με προσοχή — αυτό δημιουργεί μια coroutine χωρίς σύνδεση με τον κύκλο ζωής.
Ο αριθμός περιορίζεται από τη δεξαμενή νημάτων του dispatcher. Dispatchers.Default χρησιμοποιεί αριθμό νημάτων ίσο με τον αριθμό πυρήνων CPU. Dispatchers.IO υποστηρίζει έως 64 νήματα. Κατά την εκκίνηση περισσότερων coroutine, αυτές μπαίνουν σε ουρά.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης