onStart — είναι η μέθοδος κύκλου ζωής του Android που καλείται όταν το Activity ή το Fragment γίνονται ορατά στον χρήστη. Αυτή τη στιγμή η οθόνη εμφανίζεται στην οθόνη της συσκευής, αλλά δεν μπορεί ακόμα να αλληλεπιδράσει με τον χρήστη — η εστίαση εισόδου απουσιάζει μέχρι την κλήση του onResume. Η μέθοδος onStart είναι ιδανική για την καταχώρηση συστημικών ακροατών, σύνδεση σε υπηρεσίες γεωτοποθεσίας και εκκίνηση κινούμενων σχεδίων που πρέπει να λειτουργούν όσο το στοιχείο είναι ορατό στην οθόνη. Διαβάστε περισσότερα για τον πλήρη κύκλο ζωής του Activity στο άρθρο Activity Lifecycle.
Κύρια σημεία
onStart — η δεύτερη μέθοδος του κύκλου ζωής Activity, που καλείται από το σύστημα μετά το onCreate (ή μετά το onRestart κατά την επιστροφή από κατάσταση διακοπής). Τη στιγμή της κλήσης onStart, το Activity ή το Fragment γίνονται ορατά στην οθόνη. Ο χρήστης βλέπει τη διεπαφή, αλλά η οθόνη δεν είναι ακόμα έτοιμη για αλληλεπίδραση — η εστίαση εισόδου θα εμφανιστεί μόνο μετά το onResume.
Η μέθοδος onStart ανήκει στην “ορατή διάρκεια ζωής” (visible lifetime) του Activity — στο διάστημα μεταξύ onStart και onStop. Κατά τη διάρκεια αυτής της περιόδου, το Activity μπορεί να καλύπτεται εν μέρει από άλλα παράθυρα (για παράδειγμα, από διαφανές Activity ή παράθυρο διαλόγου), αλλά η διεπαφή χρήστη του παραμένει ορατή. Αυτό διακρίνει την ορατή διάρκεια ζωής από τη “διάρκεια ζωής στο προσκήνιο” (onResume — onPause), όταν το Activity έχει πλήρη εστίαση εισόδου.
Η κατανόηση αυτής της τριεπίπεδης ιεραρχίας είναι κρίσιμης σημασίας για τη σωστή κατανομή του κώδικα. onCreate — εφάπαξ αρχικοποίηση, onStart — σύνδεση ορατών πόρων, onResume — αποκλειστική πρόσβαση σε αποκλειστικούς πόρους. Ο προγραμματιστής που μπερδεύει αυτά τα επίπεδα κινδυνεύει να δημιουργήσει διαρροές μνήμης ή λανθασμένη συμπεριφορά της εφαρμογής κατά την εναλλαγή μεταξύ οθονών.
Στο Activity, η μέθοδος onStart καλείται κάθε φορά που η οθόνη εμφανίζεται στην οθόνη — τόσο κατά την πρώτη εκκίνηση (μετά το onCreate) όσο και κατά την επιστροφή από τη λειτουργία παρασκηνίου (μετά το onRestart). Σε αντίθεση με το onCreate, το onStart μπορεί να κληθεί πολλές φορές κατά τη διάρκεια ζωής μιας παρουσίας Activity, επομένως εδώ τοποθετείται κώδικας που πρέπει να εκτελείται κάθε φορά που εμφανίζεται η οθόνη.
class DashboardActivity : AppCompatActivity() {
private val connectivityReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
val isConnected = ... // έλεγχος ConnectivityManager
binding?.statusIndicator?.setColor(
if (isConnected) Color.GREEN else Color.RED
)
}
}
override fun onStart() {
super.onStart()
registerReceiver(
connectivityReceiver,
IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION)
)
SensorManager.getInstance().registerStepCounter()
}
override fun onStop() {
unregisterReceiver(connectivityReceiver)
SensorManager.getInstance().unregisterStepCounter()
super.onStop()
}
}
Βασικός κανόνας: όλοι οι πόροι που συνδέονται στο onStart πρέπει να απελευθερώνονται στο onStop. Αυτό εγγυάται ότι όταν το Activity είναι κρυμμένο από την οθόνη, δεν καταναλώνει μπαταρία, δεν ακούει συστημικά συμβάντα και δεν καταλαμβάνει μνήμη. Το Android Studio περιέχει κανόνες lint που προειδοποιούν για καταχώρηση BroadcastReceiver χωρίς αντίστοιχη διαγραφή.
Το onStart στο Fragment είναι στενά συνδεδεμένο με τον κύκλο ζωής του Activity-περιέκτη. Το Fragment λαμβάνει την κλήση onStart αφού το Activity στο οποίο βρίσκεται έλαβε onStart. Ωστόσο, εάν το Fragment προστέθηκε σε καθυστερημένη λειτουργία (FragmentTransaction.commit() χωρίς addToBackStack), το onStart μπορεί να κληθεί με καθυστέρηση.
class MapFragment : Fragment() {
private var mapView: MapView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
mapView = MapView(requireContext())
return mapView!!
}
override fun onStart() {
super.onStart()
mapView?.onStart()
LocationService.connect(requireContext())
}
override fun onStop() {
mapView?.onStop()
LocationService.disconnect()
super.onStop()
}
}
Ιδιαιτερότητα του Fragment.onStart: εάν το Fragment βρίσκεται σε ViewPager με offscreenPageLimit = 1, τα γειτονικά θραύσματα θα λάβουν επίσης onStart προτού γίνουν ορατά. Αυτό μπορεί να οδηγήσει σε πρόωρη καταχώρηση ακροατών. Για τέτοιες περιπτώσεις, χρησιμοποιήστε τη μέθοδο setUserVisibleHint() ή τον έλεγχο isVisible μέσα στο onStart για να καταχωρείτε ακροατές μόνο για πραγματικά ορατά θραύσματα.
Η κύρια διαφορά μεταξύ onStart και onResume — το επίπεδο δραστηριότητας της οθόνης. Το onStart σηματοδοτεί ότι το Activity είναι ορατό στην οθόνη, αλλά όχι απαραίτητα στο προσκήνιο. Το onResume σηματοδοτεί ότι το Activity βρίσκεται στο προσκήνιο και έχει εστίαση εισόδου. Η διαφορά παρουσιάζεται με το παράδειγμα παραθύρου διαλόγου: όταν ένα Dialog εμφανίζεται πάνω από το Activity, το Activity χάνει το onResume (καλείται onPause), αλλά παραμένει ορατό — onStart/onStop δεν καλούνται.
Ο πίνακας διαφορών δείχνει ξεκάθαρα σε ποια σενάρια καλείται κάθε μέθοδος:
| Σενάριο | onStart | onResume |
|---|---|---|
| Εκκίνηση εφαρμογής | Καλείται | Καλείται |
| Πάνω από το Activity ανοίγει Dialog | Δεν καλείται | onPause (απώλεια εστίασης) |
| Πάτημα κουμπιού «Αρχική» | onStop (κρυφό) | onPause → onStop |
| Επιστροφή από «Πρόσφατα» | onStart (ορατό) | onResume (εστίαση) |
| Περιστροφή οθόνης | onCreate → onStart | → onResume |
| Εισερχόμενη κλήση | onStop (κρυφό) | onPause → onStop |
Αυτός ο πίνακας βοηθά τον προγραμματιστή να αποφασίσει σε ποια μέθοδο να τοποθετήσει συγκεκριμένο κώδικα. Για παράδειγμα, εάν η εφαρμογή πρέπει να διακόπτει την αναπαραγωγή βίντεο σε οποιαδήποτε κάλυψη της οθόνης (ακόμη και με διάλογο), ο κώδικας τοποθετείται στο onPause. Εάν το βίντεο πρέπει να σταματά μόνο όταν η οθόνη είναι εντελώς κρυμμένη — ο κώδικας τοποθετείται στο onStop.
onStart — το βέλτιστο μέρος για καταχώρηση ακροατών που πρέπει να λειτουργούν μόνο όσο το Activity είναι ορατό στην οθόνη. Αυτό αφορά τρεις κύριους τύπους συστημικών στοιχείων: BroadcastReceiver για συστημικά συμβάντα, LocationListener για γεωτοποθεσία και SensorListener για αισθητήρες συσκευής.
Το BroadcastReceiver καταχωρείται δυναμικά μέσω Context.registerReceiver() στο onStart και διαγράφεται στο onStop μέσω unregisterReceiver(). Η δυναμική καταχώρηση είναι προτιμότερη από τη στατική (στο manifest), καθώς περιορίζει τη διάρκεια ζωής του δέκτη στην περίοδο ορατότητας του Activity — η εφαρμογή δεν ξυπνά από συστημικά broadcast μηνύματα όταν το Activity είναι κρυφό.
private val batteryReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent) {
val level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)
binding?.batteryText?.text = "$level%"
}
}
override fun onStart() {
super.onStart()
registerReceiver(batteryReceiver, IntentFilter(Intent.ACTION_BATTERY_CHANGED))
}
override fun onStop() {
unregisterReceiver(batteryReceiver)
super.onStop()
}
Γεωτοποθεσία και αισθητήρες — λειτουργίες που καταναλώνουν πόρους. Η αίτηση ενημερώσεων GPS στο onStart και η ακύρωση στο onStop εγγυάται ότι η εφαρμογή δεν καταναλώνει μπαταρία όταν η οθόνη είναι κρυφή. Για ακριβή ρύθμιση, χρησιμοποιείται requestLocationUpdates με ελάχιστο διάστημα και απόσταση — για παράδειγμα, 10 δευτερόλεπτα και 10 μέτρα, που παρέχει βέλτιστη ισορροπία μεταξύ ακρίβειας και κατανάλωσης ενέργειας.
Η εκκίνηση κινούμενων σχεδίων στο onStart, όχι στο onCreate, εγγυάται ότι το κινούμενο σχέδιο ξεκινά κάθε φορά που εμφανίζεται η οθόνη. Εάν ξεκινήσετε το κινούμενο σχέδιο στο onCreate, θα λειτουργήσει μόνο κατά την πρώτη δημιουργία του Activity, αλλά όχι κατά την επιστροφή από τη λειτουργία παρασκηνίου. Το onStart καλείται κάθε φορά που το Activity γίνεται ορατό, καθιστώντας το ιδανικό μέρος για εκκίνηση κυκλικών κινούμενων σχεδίων και μεταβάσεων.
private lateinit var pulseAnimator: ValueAnimator
override fun onStart() {
super.onStart()
pulseAnimator.start()
binding?.loadingIndicator?.animate()?.alpha(1f)?.start()
}
override fun onStop() {
pulseAnimator.cancel()
binding?.loadingIndicator?.animate()?.cancel()
super.onStop()
}
Για κινούμενα σχέδια που χρησιμοποιούν ObjectAnimator ή ValueAnimator, είναι σημαντικό να καλείτε cancel() στο onStop. Εάν το κινούμενο σχέδιο συνεχίζει να λειτουργεί μετά την απόκρυψη του Activity, καταναλώνει άσκοπα πόρους GPU και CPU, μειώνοντας την απόδοση της συσκευής και επιταχύνοντας την αποφόρτιση της μπαταρίας. Το Android Studio Profiler (γραφική παράσταση GPU) επιτρέπει την παρακολούθηση ενεργών κινούμενων σχεδίων και τον εντοπισμό διαρροών.
Ο κανόνας ζεύγους onStart/onStop ισχύει και για την εργασία με κάμερα προεπισκόπησης (CameraX). Το άνοιγμα της κάμερας στο onStart και το κλείσιμο στο onStop εγγυάται ότι η κάμερα δεν είναι αποκλεισμένη για άλλες εφαρμογές όταν η εφαρμογή σας δεν είναι ορατή στην οθόνη. Η παραβίαση αυτού του κανόνα είναι μία από τις συχνές αιτίες αρνητικών κριτικών στο Google Play.
Συχνές Ερωτήσεις
onStart — για ακροατές που πρέπει να λειτουργούν όσο η οθόνη είναι ορατή (BroadcastReceiver, LocationListener, SensorListener). onResume — για πόρους που απαιτούν αποκλειστική πρόσβαση (κάμερα, καταγραφή βίντεο, αναγνώριση ομιλίας). Οι ακροατές συστημικών συμβάντων δεν απαιτούν αποκλειστική πρόσβαση και μπορούν να λειτουργούν με μερική κάλυψη — καταχωρούνται στο onStart. Η κάμερα πρέπει να είναι ενεργή μόνο με πλήρη εστίαση — ανοίγει στο onResume.
Το onStart καλείται πάντα εάν το Activity μεταβαίνει σε ορατή κατάσταση. Το μόνο σενάριο χωρίς onStart — το Activity δημιουργείται και τερματίζεται αμέσως (για παράδειγμα, λόγω σφάλματος στο onCreate). Σε αυτή την περίπτωση, μετά το onCreate ακολουθεί αμέσως onDestroy. Αλλά αυτό είναι ένα σενάριο έκτακτης ανάγκης που δεν θα πρέπει να υπάρχει σε σωστά γραμμένο κώδικα.
Ναι, το onStart μπορεί να μην λάβει onResume εάν πάνω από το Activity ανοίξει αμέσως άλλο Activity ή διαφανές παράθυρο. Για παράδειγμα, εάν μετά το onCreate ξεκινήσει μια οθόνη αυθεντικοποίησης (Activity A → Activity B), στο Activity A το onStart καλείται, αλλά το onResume όχι — λαμβάνει αμέσως onPause → onStop όταν καλύπτεται από την οθόνη B.
Το onStart μπορεί να κληθεί πολλές φορές κατά τη διάρκεια ζωής μιας παρουσίας Activity. Κάθε φορά που το Activity μεταβαίνει από κρυφή κατάσταση (onStop) σε ορατή κατάσταση, καλείται το onStart. Στην πράξη, με ενεργή χρήση της εφαρμογής, το onStart μπορεί να κληθεί δεκάδες ή εκατοντάδες φορές ανά συνεδρία.
Η φόρτωση δεδομένων στο onStart δικαιολογείται εάν τα δεδομένα πρέπει να ενημερώνονται κάθε φορά που εμφανίζεται η οθόνη. Για παράδειγμα, ροή ειδήσεων ή λίστα ειδοποιήσεων. Αλλά η φόρτωση πρέπει να είναι ασύγχρονη — μέσω coroutines με lifecycleScope, για να μην μπλοκάρει το νήμα UI. Για δεδομένα που δεν αλλάζουν μεταξύ εμφανίσεων οθόνης, αρκεί να φορτωθούν μία φορά στο onCreate.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης