lifecycleScope — τι είναι, σύνδεση με το Lifecycle και εργασία στο Android

Συγγραφέας: IT Sectr Δημοσιεύτηκε: 2026-06-23 Χρόνος ανάγνωσης: 9 λεπ

lifecycleScope — είναι ένα ενσωματωμένο CoroutineScope από τη βιβλιοθήκη androidx.lifecycle, το οποίο είναι συνδεδεμένο με τον κύκλο ζωής ενός Activity, Fragment ή οποιουδήποτε LifecycleOwner και ακυρώνει αυτόματα τα coroutine όταν καταστρέφεται το component. Σύμφωνα με το Google Android Developers, 2025, το lifecycleScope επιτρέπει την ασφαλή εκτέλεση coroutine που σχετίζονται με το επίπεδο UI χωρίς τον κίνδυνο εκτέλεσης κώδικα μετά την καταστροφή του Activity ή του Fragment. Το scope ακυρώνεται αυτόματα όταν το LifecycleOwner μεταβαίνει στην κατάσταση DESTROYED.

Κύρια σημεία

  • lifecycleScope — CoroutineScope από το lifecycle-runtime-ktx, ακυρώνεται στην κατάσταση DESTROYED του Lifecycle
  • lifecycleScope.launch — εκκίνηση coroutine που ακυρώνεται αυτόματα όταν καταστρέφεται το LifecycleOwner
  • launchWhenStarted / launchWhenResumed — παρωχημένες μέθοδοι, αντικαταστάθηκαν από repeatOnLifecycle
  • repeatOnLifecycle — σύγχρονο API για εκκίνηση coroutine που παρακολουθούν μια συγκεκριμένη κατάσταση Lifecycle
  • Dispatchers.Main.immediate — προεπιλεγμένος dispatcher για το lifecycleScope

Τι είναι το lifecycleScope στο Android;

lifecycleScope — είναι μια ιδιότητα επέκτασης στη διεπαφή LifecycleOwner (Activity, Fragment, Service) που παρέχει ένα έτοιμο CoroutineScope συνδεδεμένο με τον πλήρη κύκλο ζωής του component. Όταν το LifecycleOwner φτάσει στην κατάσταση DESTROYED, το lifecycleScope ακυρώνει αυτόματα όλα τα ενεργά coroutine.

kotlin
// Σε Fragment ή Activity
lifecycleScope.launch {
    delay(1000)
    showSnackbar("Γεια!")
}

Σε αντίθεση με το viewModelScope, το lifecycleScope ακυρώνεται σε κάθε καταστροφή του LifecycleOwner — συμπεριλαμβανομένης της περιστροφής οθόνης. Αυτό το καθιστά ιδανικό για λειτουργίες που πρέπει να ζουν μόνο όσο μια συγκεκριμένη οθόνη είναι ορατή.

Πού είναι διαθέσιμο το lifecycleScope

Το lifecycleScope είναι διαθέσιμο παντού όπου υπάρχει LifecycleOwner:

  • Activity — Το AppCompatActivity κληρονομεί το LifecycleOwner
  • Fragment — Το Fragment κληρονομεί το LifecycleOwner
  • LifecycleService — υπηρεσία με κύκλο ζωής
  • ProcessLifecycleOwner — κύκλος ζωής ολόκληρης της εφαρμογής
  • Προσαρμοσμένο LifecycleOwner — οποιαδήποτε αντικείμενα που υλοποιούν το LifecycleOwner

Πώς λειτουργεί το lifecycleScope: Lifecycle και αυτόματη ακύρωση

Ο μηχανισμός αυτόματης ακύρωσης του lifecycleScope βασίζεται σε εγγραφή στα συμβάντα Lifecycle. Όταν το Lifecycle πέσει κάτω από το CREATED στο DESTROYED, το scope ακυρώνεται.

Καταστάσεις Lifecycle

ΚατάστασηΠεριγραφήScope ενεργό
CREATEDLifecycleOwner δημιουργήθηκε, το onCreate εκτελέστηκεΝαι
STARTEDLifecycleOwner ορατό (onStart)Ναι
RESUMEDLifecycleOwner σε πρώτο πλάνο (onResume)Ναι
DESTROYEDLifecycleOwner καταστράφηκε (onDestroy)Όχι (scope ακυρώθηκε)

Εσωτερική δομή του lifecycleScope

Το lifecycleScope δημιουργείται ως CoroutineScope(SupervisorJob() + Dispatchers.Main.immediate) και αποθηκεύεται μέσα στο Lifecycle. Κατά τη μετάβαση του Lifecycle στην κατάσταση DESTROYED, καλείται το scope.cancel(). Ο μηχανισμός υλοποιείται μέσω του LifecycleEventObserver, ο οποίος εγγράφεται στα συμβάντα κύκλου ζωής κατά την πρώτη πρόσβαση στο scope.

Συμπεριφορά κατά την περιστροφή

Κατά την περιστροφή οθόνης, το Activity καταστρέφεται (onDestroy) και δημιουργείται εκ νέου. Το lifecycleScope ακυρώνεται μαζί με το παλιό Activity και μια νέα παρουσία scope δημιουργείται για το νέο Activity. Αυτή είναι μια θεμελιώδης διαφορά από το viewModelScope, το οποίο διατηρείται κατά την περιστροφή.

API lifecycleScope: launch, launchWhen και repeatOnLifecycle

Η βιβλιοθήκη lifecycle παρέχει διάφορους τρόπους εκκίνησης coroutine μέσω του lifecycleScope. Ας δούμε την εξέλιξη του API από παρωχημένες μεθόδους σε σύγχρονες.

lifecycleScope.launch — βασική εκκίνηση

Ο απλούστερος τρόπος — lifecycleScope.launch { ... }. Το coroutine ξεκινά αμέσως και ακυρώνεται στο DESTROYED. Ωστόσο, μπορεί να εκτελεί κώδικα ακόμα και όταν το UI δεν είναι ορατό (π.χ. στο παρασκήνιο μετά το onStop). Αυτό δεν είναι πάντα επιθυμητό.

Παρωχημένες: launchWhenCreated / launchWhenStarted / launchWhenResumed

Αυτές οι μέθοδοι ανέστελλαν την εκτέλεση του coroutine όταν το Lifecycle έπεφτε κάτω από την καθορισμένη κατάσταση και τη συνέχιζαν κατά την επιστροφή. Ωστόσο, επισημάνθηκαν ως @Deprecated στο lifecycle-runtime-ktx 2.6.0, επειδή:

  • Δεν ακύρωναν το coroutine — μόνο το ανέστελλαν
  • Οδηγούσαν σε συσσώρευση coroutine σε εκκρεμότητα που καταναλώνουν μνήμη
  • Δημιουργούσαν race condition κατά τη γρήγορη εναλλαγή καταστάσεων

Σύγχρονο API: repeatOnLifecycle

repeatOnLifecycle — ο προτεινόμενος από την Google τρόπος εκκίνησης coroutine συγχρονισμένων με τον κύκλο ζωής. Ακυρώνει και επανεκκινεί το coroutine κάθε φορά που το Lifecycle φτάνει σε μια καθορισμένη κατάσταση.

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        viewModel.uiState.collect { state ->
            updateUI(state)
        }
    }
}

Το coroutine που μεταβιβάζεται στο repeatOnLifecycle ξεκινά όταν το Lifecycle φτάσει στο STARTED και ακυρώνεται όταν πέσει κάτω από το STARTED. Κατά την επιστροφή στο STARTED, το coroutine επανεκκινείται από την αρχή. Αυτό είναι ασφαλές και αποτελεσματικό — κανένα coroutine δεν παραμένει σε αναστολή.

flowWithLifecycle — για Flow

Για τη συλλογή δεδομένων από Flow με βάση τον κύκλο ζωής, υπάρχει ο τελεστής flowWithLifecycle. Σταματά και συνεχίζει αυτόματα τη συλλογή όταν αλλάζει η κατάσταση του Lifecycle:

kotlin
viewModel.uiState
    .flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
    .onEach { state -> updateUI(state) }
    .launchIn(lifecycleScope)

Ο τελεστής flowWithLifecycle — ο πιο συνοπτικός τρόπος ασφαλούς εγγραφής σε Flow στο επίπεδο UI.

Παραδείγματα χρήσης του lifecycleScope

Ας δούμε τρία πραγματικά σενάρια χρήσης του lifecycleScope σε μια εφαρμογή Android σε Kotlin.

Παράδειγμα 1: Εγγραφή σε ενημερώσεις τοποθεσίας μόνο όταν η οθόνη είναι ορατή

kotlin
class MapFragment : Fragment() {

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        lifecycleScope.launch {
            repeatOnLifecycle(Lifecycle.State.STARTED) {
                locationProvider.observeLocation().collect { loc ->
                    updateMapMarker(loc)
                }
            }
        }
    }
}

Το coroutine ξεκινά όταν το fragment γίνεται ορατό (STARTED) και ακυρώνεται όταν φεύγει από την οθόνη (STOPPED). Αν ο χρήστης μεταβεί σε άλλη εφαρμογή, οι ενημερώσεις τοποθεσίας δεν καταναλώνουν μπαταρία.

Παράδειγμα 2: Εκκίνηση κινούμενου σχεδίου κατά την έναρξη του fragment

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.RESUMED) {
        animateFadeIn(titleView)
        delay(200)
        animateSlideUp(contentView)
    }
}

Το κινούμενο σχέδιο ξεκινά μόνο όταν το fragment είναι σε πρώτο πλάνο (RESUMED). Αν ο χρήστης ελαχιστοποιήσει την εφαρμογή κατά τη διάρκεια του κινούμενου σχεδίου, το coroutine ακυρώνεται και κατά την επιστροφή το κινούμενο σχέδιο ξεκινά ξανά.

Παράδειγμα 3: Περιοδικός συγχρονισμός δεδομένων σε ορατή οθόνη

kotlin
lifecycleScope.launch {
    repeatOnLifecycle(Lifecycle.State.STARTED) {
        while (isActive) {
            syncData()
            delay(30_000L)
        }
    }
}

Τα δεδομένα συγχρονίζονται κάθε 30 δευτερόλεπτα, αλλά μόνο όταν η οθόνη είναι ορατή. Το isActive ελέγχει αν το coroutine δεν έχει ακυρωθεί, διασφαλίζοντας ασφαλή έξοδο από τον βρόχο κατά την αποχώρηση από την οθόνη.

lifecycleScope εναντίον viewModelScope: σενάρια εφαρμογής

Και τα δύο scope είναι συνδεδεμένα με τον κύκλο ζωής, αλλά με διαφορετικές πτυχές του. Η κατανόηση της διαφοράς είναι κρίσιμη για τη σωστή αρχιτεκτονική εφαρμογών Android.

Βασική διαφορά

viewModelScope είναι συνδεδεμένο με το ViewModel, το οποίο επιβιώνει της περιστροφής οθόνης. lifecycleScope είναι συνδεδεμένο με το LifecycleOwner (Activity/Fragment), το οποίο κατά την περιστροφή καταστρέφεται και δημιουργείται εκ νέου. Αυτό καθορίζει τα σενάρια εφαρμογής τους.

Πότε να χρησιμοποιείτε lifecycleScope

  • Εγγραφή σε συμβάντα συστήματος (τοποθεσία, αισθητήρες, κάμερα)
  • Κινούμενα σχέδια και εφέ UI συνδεδεμένα με μια συγκεκριμένη οθόνη
  • Τμηματική φόρτωση δεδομένων με βάση την ορατότητα οθόνης
  • Λειτουργίες που πρέπει να σταματούν κατά την αποχώρηση από την οθόνη

Πότε να χρησιμοποιείτε viewModelScope

  • Φόρτωση δεδομένων από Repository
  • Επιχειρηματική λογική που πρέπει να επιβιώσει περιστροφής
  • Προσωρινή αποθήκευση και επεξεργασία δεδομένων
  • Οποιεσδήποτε λειτουργίες των οποίων το αποτέλεσμα χρειάζεται μετά από περιστροφή

Συνδυασμένη χρήση

Στην πράξη, ο συνδυασμός και των δύο scope είναι συχνός: το viewModelScope φορτώνει δεδομένα και διαχειρίζεται την κατάσταση, το lifecycleScope εγγράφεται σε Flow από το ViewModel λαμβάνοντας υπόψη τον κύκλο ζωής της οθόνης. Αυτός ο διαχωρισμός ευθυνών θεωρείται best practice στη σύγχρονη ανάπτυξη Android.

Συνηθισμένα λάθη κατά τη χρήση του lifecycleScope

Ας δούμε τέσσερα συνηθισμένα λάθη που κάνουν οι προγραμματιστές κατά τη χρήση του lifecycleScope.

Λάθος 1: Χρήση lifecycleScope αντί για viewModelScope για φόρτωση δεδομένων

Εάν ξεκινήσετε τη φόρτωση δεδομένων σε lifecycleScope.launch, κατά την περιστροφή οθόνης το coroutine θα ακυρωθεί και τα δεδομένα θα πρέπει να φορτωθούν ξανά. Χρησιμοποιήστε viewModelScope για μακροχρόνιες λειτουργίες. lifecycleScope — μόνο για εργασίες που σχετίζονται με UI.

Λάθος 2: Συλλογή Flow χωρίς repeatOnLifecycle

Η άμεση κλήση viewModel.someFlow.collect { ... } μέσα σε lifecycleScope.launch συνεχίζει να συλλέγει δεδομένα ακόμα και όταν η οθόνη δεν είναι ορατή. Αυτό μπορεί να οδηγήσει σε ενημερώσεις UI στο παρασκήνιο και περιττή επιβάρυνση. Πάντα να χρησιμοποιείτε repeatOnLifecycle ή flowWithLifecycle.

Λάθος 3: Λήθη ακύρωσης κατά την αποχώρηση από την οθόνη

Παρόλο που το lifecycleScope ακυρώνεται στο DESTROYED, ο κώδικας μετά από ένα σημείο αναστολής (suspend) μπορεί να μην εκτελεστεί σε περίπτωση ξαφνικής ακύρωσης. Μην βασίζεστε στην εκτέλεση κώδικα μετά από κλήση suspend, εκτός εάν χρησιμοποιείτε NonCancellable.

Λάθος 4: Χρήση παρωχημένου launchWhenStarted αντί για repeatOnLifecycle

Το launchWhenStarted και τα ανάλογά του δεν ακυρώνουν το coroutine, μόνο το αναστέλλουν. Εάν η οθόνη εναλλάσσεται πολλές φορές μεταξύ πρώτου και δεύτερου πλάνου, το coroutine συσσωρεύει αναβληθείσες κλήσεις. Μεταβείτε στο repeatOnLifecycle — αυτός είναι ο μόνος σωστός τρόπος συγχρονισμού με το Lifecycle.

Συχνές Ερωτήσεις

Ποια είναι η διαφορά μεταξύ lifecycleScope και GlobalScope;

lifecycleScope ακυρώνεται αυτόματα όταν καταστρέφεται το LifecycleOwner. GlobalScope ζει καθ' όλη τη διάρκεια λειτουργίας της εφαρμογής. Το coroutine στο lifecycleScope δεν μπορεί να ενημερώσει το UI μετά την καταστροφή του component, στο GlobalScope μπορεί, οδηγώντας σε σφάλματα. Πάντα να χρησιμοποιείτε lifecycleScope στο επίπεδο UI.

Μπορεί να χρησιμοποιηθεί το lifecycleScope σε ViewModel;

Όχι, το ViewModel δεν είναι LifecycleOwner, επομένως το lifecycleScope δεν είναι διαθέσιμο σε αυτό. Το ViewModel χρησιμοποιεί viewModelScope. Εάν ο κώδικας πρέπει να εκτελείται και στα δύο πλαίσια — εξάγετε τη λογική σε use case ή repository με συναρτήσεις suspend.

Τι συμβαίνει όταν το repeatOnLifecycle καλείται επανειλημμένα;

Κάθε κλήση repeatOnLifecycle δημιουργεί ένα νέο coroutine που εκτελεί το μπλοκ όταν το Lifecycle φτάσει στην καθορισμένη κατάσταση. Εάν το repeatOnLifecycle κληθεί δύο φορές για την ίδια κατάσταση, και τα δύο μπλοκ θα εκτελεστούν ανεξάρτητα. Συνήθως αρκεί μία κλήση στο onViewCreated.

Μπορεί να οριστεί προσαρμοσμένος Dispatcher για το lifecycleScope;

Ο dispatcher του lifecycleScope δεν μπορεί να αλλάξει άμεσα — χρησιμοποιεί Dispatchers.Main.immediate. Μέσα στο μπλοκ coroutine, μπορείτε να μεταβείτε σε άλλο dispatcher μέσω withContext. Για δοκιμές, χρησιμοποιήστε TestDispatcher με LifecycleOwner.

Το lifecycleScope ακυρώνεται στο onPause ή στο onDestroy;

Το lifecycleScope ακυρώνεται όταν το LifecycleOwner μεταβαίνει στην κατάσταση DESTROYED (μετά το onDestroy). Οι απλές κλήσεις lifecycleScope.launch δεν ακυρώνονται στο onPause ή στο onStop. Για παύση κατά τη μετάβαση στο παρασκήνιο, χρησιμοποιήστε repeatOnLifecycle(STARTED) ή repeatOnLifecycle(RESUMED).

Σύνοψη

  • lifecycleScope — CoroutineScope συνδεδεμένο με LifecycleOwner, αυτόματα ακυρωμένο στο DESTROYED μέσω LifecycleEventObserver
  • Dispatchers.Main.immediate — προεπιλεγμένος dispatcher που διασφαλίζει ασφαλή ενημέρωση UI χωρίς περιττές εναλλαγές
  • repeatOnLifecycle — σύγχρονο API για εκκίνηση coroutine σε καθορισμένη κατάσταση Lifecycle με αυτόματη ακύρωση και επανεκκίνηση
  • flowWithLifecycle — τελεστής για ασφαλή συλλογή Flow από UI με βάση τον κύκλο ζωής
  • launchWhenStarted έχει παρωχηθεί — αντί για αναστολή, χρησιμοποιήστε repeatOnLifecycle που ακυρώνει το coroutine, δεν το αναστέλλει
  • lifecycleScope εναντίον viewModelScope — lifecycleScope για λειτουργίες UI (κινούμενα σχέδια, τοποθεσία), viewModelScope για δεδομένα και επιχειρηματική λογική
  • Περιστροφή οθόνης — lifecycleScope ακυρώνεται κατά την περιστροφή, viewModelScope διατηρείται· επιλέξτε scope ανάλογα με την εργασία

Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση

Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.

Συζήτηση έργου

Διαβάστε επίσης