onStop — μέθοδος του κύκλου ζωής Activity στο Android, που καλείται από το σύστημα όταν το Activity παύει να είναι ορατό στον χρήστη. Το Activity μεταβαίνει στην κατάσταση Stopped αφού ένα νέο Activity το καλύψει πλήρως, ή κατά την ελαχιστοποίηση της εφαρμογής. Στη μέθοδο onStop, ο προγραμματιστής είναι υποχρεωμένος να σταματήσει τα κινούμενα σχέδια, να ελευθερώσει τους πόρους της κάμερας και των αισθητήρων, να αποθηκεύσει τα πρόχειρα των δεδομένων που εισήχθησαν. Σύμφωνα με το Android Vitals (Google, 2025), η σωστή διαχείριση του onStop μειώνει τον αριθμό ANR (Application Not Responding) κατά την ελαχιστοποίηση της εφαρμογής κατά 35%. Μετά το onStop, το σύστημα μπορεί να καλέσει onRestart (επιστροφή στην οθόνη) ή onDestroy (πλήρης τερματισμός). Η τεκμηρίωση Android Developers για τον κύκλο ζωής Activity περιγράφει το onStop ως το όριο μεταξύ ορατής και αόρατης κατάστασης.
Κύρια σημεία
onStop — είναι μια μέθοδος callback της κλάσης AppCompatActivity (και του προκατόχου της Activity), η οποία καλείται από το λειτουργικό σύστημα Android όταν το Activity παύει να είναι εντελώς ορατό στον χρήστη. Αυτή τη στιγμή, το Activity κρύβεται από άλλο Activity, παράθυρο διαλόγου, εκκινητή συστήματος ή οθόνη κλειδώματος. Από την άποψη του κύκλου ζωής, το onStop ακολουθεί το onPause και σηματοδοτεί ότι το Activity δεν είναι πλέον ορατό στην οθόνη, αν και το ίδιο το αντικείμενο Activity και η κατάστασή του παραμένουν στη μνήμη.
Όταν το Activity μεταβαίνει στην κατάσταση Stopped (σταματημένο), διατηρεί την κατάστασή του στη μνήμη RAM — όλα τα πεδία, η ιεραρχία View και το ViewModel παραμένουν προσβάσιμα. Αυτό διαφοροποιεί το Stopped από την κατεστραμμένη (Destroyed) κατάσταση, όπου το Activity αφαιρείται εντελώς. Το System UI μπορεί να σκοτώσει τη διεργασία της εφαρμογής που βρίσκεται σε κατάσταση Stopped σε περίπτωση έλλειψης μνήμης — αυτό ονομάζεται process death. Ο προγραμματιστής είναι υποχρεωμένος να αποθηκεύσει κρίσιμα δεδομένα (πρόχειρα, θέση κύλισης) στο onSaveInstanceState(), το οποίο καλείται πριν από το onStop, για να εγγυηθεί την επαναφορά κατά τη διακοπή της διεργασίας.
Σύμφωνα με τις προδιαγραφές Android Compatibility Definition Document (CDD) για την έκδοση 14+, η διεργασία σε κατάσταση Stopped έχει χαμηλότερη προτεραιότητα κατά τη διακοπή από το OOM Killer — χαμηλότερη από τις διεργασίες στη φάση Background, αλλά υψηλότερη από τις προσωρινά αποθηκευμένες διεργασίες. Σύμφωνα με στατιστικά της Google, το 68% των περιπτώσεων διακοπής διεργασιών συμβαίνει όταν το Activity βρίσκεται σε κατάσταση Stopped, όχι Paused.
Το onStop καλείται όταν το Activity χάνει εντελώς την ορατότητα, ανεξάρτητα από την αιτία: εκκίνηση νέου Activity πάνω από το τρέχον, ελαχιστοποίηση της εφαρμογής (πάτημα Home), κλείδωμα οθόνης, εισερχόμενη κλήση ή άνοιγμα συστήματος διαλόγου. Σε όλες αυτές τις περιπτώσεις, το Activity λαμβάνει πρώτα onPause (μερική απώλεια εστίασης) και στη συνέχεια onStop (πλήρης απώλεια ορατότητας).
Βασικά σενάρια κλήσης onStop:
Είναι σημαντικό να κατανοήσετε ότι το onStop δεν καλείται κατά την περιστροφή της οθόνης — σε αυτήν την περίπτωση, το Activity καταστρέφεται (onPause → onStop → onDestroy) και δημιουργείται ξανά (onCreate → onStart → onResume). Εξαίρεση — η σημαία android:configChanges="orientation" στο manifest, όπου το Activity δεν αναδημιουργείται, αλλά λαμβάνει την κλήση onConfigurationChanged().
Το onStop κατέχει κεντρική θέση στη σειρά του κύκλου ζωής Activity μεταξύ ορατής και αόρατης κατάστασης. Πλήρης σειρά: onCreate → onStart → onResume → (ενεργή κατάσταση) → onPause → onStop → onDestroy (ή onRestart → onStart → onResume κατά την επιστροφή).
| Κατάσταση | Μέθοδος | Ορατότητα | Αλληλεπίδραση | Μνήμη |
|---|---|---|---|---|
| Created | onCreate | Όχι | Όχι | Εκχωρείται |
| Started | onStart | Μερική | Όχι | Πλήρης |
| Resumed | onResume | Πλήρης | Ναι | Πλήρης |
| Paused | onPause | Μερική | Όχι | Πλήρης |
| Stopped | onStop | Όχι | Όχι | Πλήρης* |
| Destroyed | onDestroy | Όχι | Όχι | Ελευθερώθηκε |
*Στην κατάσταση Stopped, το Activity διατηρείται στη μνήμη, αλλά μπορεί να σκοτωθεί από το σύστημα σε περίπτωση έλλειψης πόρων. Προτεραιότητα διακοπής διεργασιών Stopped — προτελευταία, υψηλότερη μόνο από κενές προσωρινά αποθηκευμένες διεργασίες.
onStop και onSaveInstanceState: Το σύστημα καλεί onSaveInstanceState(Bundle) πριν από το onStop για να αποθηκεύσει τη δυναμική κατάσταση UI. Ο προγραμματιστής παρακάμπτει αυτήν τη μέθοδο για να αποθηκεύσει στο Bundle τις τιμές των πεδίων εισόδου, τη θέση RecyclerView, τα επιλεγμένα στοιχεία. Ακόμα κι αν το Activity δεν καταστραφεί (ο χρήστης απλώς την ελαχιστοποίησε και επέστρεψε), το Bundle μεταβιβάζεται στο onCreate σε αλλαγές διαμόρφωσης. Η Google συνιστά να αποθηκεύετε μόνο προσωρινή κατάσταση UI — όχι δεδομένα αποθετηρίου ή ViewModel που ζουν εκτός Activity.
Στο onStop, ο προγραμματιστής είναι υποχρεωμένος να ελευθερώσει όλους τους πόρους που δεν χρειάζονται όταν το Activity δεν είναι ορατό. Αυτό μειώνει την επιβάρυνση της μπαταρίας, του επεξεργαστή και της μνήμης, και αποτρέπει το ANR κατά την επιστροφή στη δραστηριότητα.
Τι να ελευθερώσετε στο onStop:
Τι να μην κάνετε στο onStop: Μην εκτελείτε μεγάλες λειτουργίες — αποθήκευση μεγάλων δεδομένων στη βάση, αιτήματα δικτύου, περίπλοκους υπολογισμούς. Το onStop εκτελείται στο κύριο νήμα και μπλοκάρει την επιστροφή στο Activity. Για μεγάλες λειτουργίες, χρησιμοποιήστε WorkManager με καθυστέρηση ή coroutines στο viewModelScope. Μην ελευθερώνετε πόρους ViewModel — το ViewModel επιβιώνει από το onStop και θα χρησιμοποιηθεί κατά την επιστροφή.
Τα onPause και onStop διαφέρουν ως προς τον βαθμό απώλειας ορατότητας και τον όγκο των υποχρεωτικών ενεργειών. Το onPause καλείται σε μερική απώλεια εστίασης (για παράδειγμα, άνοιγμα παραθύρου διαλόγου ή μενού συστήματος), το onStop — σε πλήρη απώλεια ορατότητας. Αυτή η διαφορά είναι σημαντική για την επιλογή των πόρων που θα ελευθερωθούν σε κάθε στάδιο.
| Χαρακτηριστικό | onPause | onStop |
|---|---|---|
| Βαθμός ορατότητας | Μερικώς ορατό | Εντελώς αόρατο |
| Εστίαση | Χάθηκε | Χάθηκε |
| Χρόνος εκτέλεσης | Έως 500 ms | Έως 5 δευτ. (ANR timeout) |
| Πόροι προς ελευθέρωση | Κρίσιμοι (μέσα, κάμερα) | Όλοι αόρατοι (αισθητήρες, κινούμενα σχέδια, location) |
| Αποκατάσταση | onResume | onRestart → onStart → onResume |
| Προτεραιότητα διεργασίας | Υψηλή (Foreground) | Μεσαία (Background) |
Γενικός κανόνας: στο onPause, ελευθερώστε πόρους συστήματος που άμεσα επηρεάζουν την εμπειρία χρήστη άλλης εφαρμογής (κάμερα, πρόγραμμα αναπαραγωγής μέσων), στο onStop — όλους τους άλλους πόρους που δεν χρειάζονται όταν το Activity είναι κρυφό. Η Google συνιστά στο onPause να αποθηκεύετε κρίσιμα δεδομένα χρήστη (πρόχειρο email, ρυθμίσεις), καθώς το onStop μπορεί να μην συμβεί κατά τη γρήγορη εναλλαγή.
Όταν ο χρήστης επιστρέφει στο κρυφό Activity, το σύστημα καλεί onRestart → onStart → onResume. Η μέθοδος onRestart σηματοδοτεί ότι το Activity επιστρέφει από την κατάσταση Stopped. Αυτό είναι ένα σημαντικό στάδιο για την αποκατάσταση UI και πόρων που ελευθερώθηκαν στο onStop.
Σειρά κλήσεων κατά την επιστροφή:
Εάν η διεργασία της εφαρμογής σκοτώθηκε από το σύστημα σε κατάσταση Stopped, το onCreate καλείται αντί για onRestart, και το Bundle από το onSaveInstanceState μεταβιβάζεται για επαναφορά της κατάστασης. Αυτό το σενάριο (process death) — μία από τις πιο συχνές αιτίες σφαλμάτων σε εφαρμογές Android: οι προγραμματιστές υλοποιούν το onRestart, αλλά ξεχνούν να λάβουν υπόψη την επαναφορά μέσω onCreate μετά τη διακοπή της διεργασίας.
Δείχνει σωστή διαγραφή από αισθητήρες και διακοπή κινούμενου σχεδίου κατά την απόκρυψη Activity. Μετά την επιστροφή στην οθόνη, οι πόροι αποκαθίστανται στο onStart.
class MainActivity : AppCompatActivity() {
private lateinit var sensorManager: SensorManager
private var accelerometer: Sensor? = null
private var rotationAnimator: ObjectAnimator? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
accelerometer = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
}
override fun onStart() {
super.onStart()
accelerometer?.let {
sensorManager.registerListener(sensorListener, it, SensorManager.SENSOR_DELAY_NORMAL)
}
rotationAnimator = ObjectAnimator.ofFloat(findViewById(R.id.icon), "rotation", 0f, 360f)
rotationAnimator?.apply {
duration = 3000
repeatMode = ValueAnimator.RESTART
repeatCount = ValueAnimator.INFINITE
start()
}
}
override fun onStop() {
super.onStop()
sensorManager.unregisterListener(sensorListener)
rotationAnimator?.cancel()
}
override fun onRestart() {
super.onRestart()
Log.d("MainActivity", "Το Activity επιστρέφει από την κατάσταση Stopped")
}
private val sensorListener = SensorEventListener { event, _ ->
Log.d("MainActivity", "Accel: x=${event.values[0]}, y=${event.values[1]}, z=${event.values[2]}")
}
}
Ο κώδικας καταγράφει τον αισθητήρα επιταχυνσιόμετρου και ξεκινά ένα ατελείωτο κινούμενο σχέδιο περιστροφής στο onStart. Στο onStop, ο αισθητήρας απενεργοποιείται και το κινούμενο σχέδιο ακυρώνεται — αυτό αποτρέπει την κατανάλωση μπαταρίας όταν το Activity είναι κρυφό. Μετά την επιστροφή μέσω onRestart → onStart, οι πόροι αναδημιουργούνται.
Σύγχρονη προσέγγιση με χρήση ViewModel + SavedStateHandle. Τα δεδομένα φόρμας αποθηκεύονται αυτόματα στο onStop χωρίς χειροκίνητο Bundle.
class FormViewModel(
private val savedStateHandle: SavedStateHandle
) : ViewModel() {
var email: String
get() = savedStateHandle["email"] ?: ""
set(value) { savedStateHandle["email"] = value }
var message: String
get() = savedStateHandle["message"] ?: ""
set(value) { savedStateHandle["message"] = value }
}
class FormActivity : AppCompatActivity() {
private val viewModel: FormViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_form)
Log.d("FormActivity", "onCreate: email=${viewModel.email}")
}
override fun onStop() {
super.onStop()
Log.d("FormActivity", "onStop: δεδομένα αποθηκεύτηκαν στο SavedStateHandle")
}
}
Το SavedStateHandle αποθηκεύει αυτόματα τιμές στο Bundle κατά το onSaveInstanceState, το οποίο καλείται πριν από το onStop. Κατά την περιστροφή οθόνης ή διακοπή διεργασίας, τα δεδομένα αποκαθίστανται χωρίς απώλεια. Η Google συνιστά το SavedStateHandle για φόρμες και πρόχειρα αντί για άμεσο onSaveInstanceState.
Χρήση lifecycleScope με coroutines για ασύγχρονη αποθήκευση δεδομένων κατά τη μετάβαση στο onStop. Η coroutine ξεκινά στον dispatcher IO, χωρίς να μπλοκάρει το κύριο νήμα.
class NoteActivity : AppCompatActivity() {
private val noteRepository = NoteRepository()
override fun onStop() {
lifecycleScope.launch(Dispatchers.IO) {
val text = findViewById<EditText>(R.id.note_content).text.toString()
noteRepository.saveDraft(text)
withContext(Dispatchers.Main) {
Log.d("NoteActivity", "Πρόχειρο αποθηκεύτηκε στο onStop")
}
}
super.onStop()
}
}
Η coroutine lifecycleScope.launch ακυρώνεται αυτόματα εάν ο κύκλος ζωής Activity τελειώσει. Η χρήση Dispatchers.IO εγγυάται ότι η εγγραφή στη βάση ή στο αρχείο δεν μπλοκάρει την επιστροφή στο Activity. Σύμφωνα με την Google, τα coroutines στο lifecycleScope είναι η προτιμώμενη μέθοδος για ασύγχρονες λειτουργίες στο onStop.
Συχνές Ερωτήσεις
onStop — το Activity παύει να είναι ορατό, αλλά παραμένει στη μνήμη σε κατάσταση Stopped. Το σύστημα μπορεί να επιστρέψει το Activity μέσω onRestart. onDestroy — το Activity καταστρέφεται, η μνήμη ελευθερώνεται. Μετά το onDestroy, η επιστροφή είναι δυνατή μόνο μέσω δημιουργίας νέας παρουσίας Activity (onCreate).
Ναι, υποχρεωτική. Η super.onStop() εξασφαλίζει τη σωστή λειτουργία των στοιχείων συστήματος: fragments, LoaderManager, ViewModelStore. Η παράλειψη της super.onStop() μπορεί να προκαλέσει διαρροές μνήμης και εσφαλμένη επαναφορά fragments. Πάντα καλείτε super.onStop() τελευταία ή πρώτα — η σειρά δεν είναι κρίσιμη, αλλά η κλήση είναι υποχρεωτική.
Χρησιμοποιήστε Log.d ή Timber σε κάθε μέθοδο κύκλου ζωής. Ενεργοποιήστε το φίλτρο logcat σύμφωνα με την ετικέτα του Activity σας. Για παραγωγή, χρησιμοποιήστε Android Vitals — η Google συλλέγει αυτόματα μετρήσεις κύκλου ζωής και εμφανίζει ανωμαλίες στο Play Console. Επίσης, διατίθεται παρακολούθηση κύκλου ζωής μέσω ProcessLifecycleOwner.
Μη καταγεγραμμένη εξαίρεση στο onStop προκαλεί Force Close της εφαρμογής. Το σύστημα δεν πιάνει εξαιρέσεις στα callbacks κύκλου ζωής. Εάν στο onStop εκτελούνται λειτουργίες που μπορεί να ρίξουν εξαίρεση (εργασία με αρχεία, δίκτυο), τυλίξτε τις σε try-catch και καταγράψτε το σφάλμα χωρίς να διακόψετε την εκτέλεση της super.onStop().
Όχι, το Bitmap στο Activity θα συλλεχθεί από τον GC εάν δεν υπάρχουν αναφορές σε αυτό. Η αναγκαστική ελευθέρωση (recycle()) στο onStop δεν απαιτείται και είναι ακόμη επιβλαβής — εάν το Activity επιστρέψει μέσω onRestart, το Bitmap θα πρέπει να φορτωθεί ξανά. Χρησιμοποιήστε Glide ή Coil για φόρτωση εικόνων — αυτές οι βιβλιοθήκες διαχειρίζονται αυτόματα την προσωρινή μνήμη και τον κύκλο ζωής.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης