onCreate — είναι η πρώτη και μοναδική υποχρεωτική μέθοδος του κύκλου ζωής Activity και Fragment στο Android. Το σύστημα την καλεί μία φορά κατά τη δημιουργία του component, μεταβιβάζοντας την παράμετρο Bundle με την προηγουμένως αποθηκευμένη κατάσταση. Μέσα στο onCreate ο προγραμματιστής αρχικοποιεί τη διεπαφή χρήστη, συνδέει τα στοιχεία View, ρυθμίζει τους χειριστές συμβάντων και επαναφέρει δεδομένα από το savedInstanceState. Χωρίς σωστή υλοποίηση του onCreate, καμία εφαρμογή Android δεν μπορεί να εκκινηθεί — είναι το σημείο εισόδου για κάθε οθόνη. Διαβάστε περισσότερα για τον γενικό κύκλο ζωής Activity στο άρθρο Activity Lifecycle.
Κύρια σημεία
onCreate — μια μέθοδος callback που καλεί το Android κατά τη δημιουργία μιας νέας παρουσίας Activity ή Fragment. Αυτό είναι το πρώτο σημείο εισόδου στον κώδικα της οθόνης χρήστη: πριν από την κλήση του onCreate, δεν εκτελείται κανένας κώδικας χρήστη. Το σύστημα μεταβιβάζει στη μέθοδο την παράμετρο Bundle, η οποία είτε περιέχει προηγουμένως αποθηκευμένα δεδομένα (κατά την αναδημιουργία) είτε είναι null (κατά την πρώτη εκκίνηση).
Η μέθοδος onCreate ορίζεται στην κλάση android.app.Activity και στην κλάση androidx.fragment.app.Fragment. Και οι δύο παραλλαγές εκτελούν παρόμοιες εργασίες: αρχικοποίηση του component, ρύθμιση UI και επαναφορά κατάστασης. Ωστόσο, η συγκεκριμένη υλοποίηση διαφέρει — το Activity χρησιμοποιεί setContentView για τη φόρτωση της διάταξης, ενώ το Fragment επιστρέφει View μέσω του onCreateView. Ο προγραμματιστής υποχρεούται να παρακάμψει τουλάχιστον το onCreate στο Activity — χωρίς αυτό, το Android δεν μπορεί να εμφανίσει την οθόνη.
Το onCreate καλείται αυστηρά μία φορά κατά τη διάρκεια ολόκληρου του κύκλου ζωής της παρουσίας Activity. Ακόμη και κατά την περιστροφή οθόνης, η νέα παρουσία Activity λαμβάνει μια νέα κλήση onCreate με το Bundle από την προηγούμενη παρουσία. Αυτή η ιδιότητα καθιστά το onCreate ιδανικό μέρος για εφάπαξ αρχικοποίηση: φόρτωση δεδομένων, δημιουργία προσαρμογέων, ρύθμιση component DI μέσω Dagger ή Hilt.
Στο Activity, η μέθοδος onCreate εκτελεί τέσσερις βασικές εργασίες: φόρτωση διάταξης layout, αρχικοποίηση στοιχείων View, επαναφορά κατάστασης από Bundle και ρύθμιση πρωταρχικών χειριστών συμβάντων. Ο υποχρεωτικός ελάχιστος κώδικας στο onCreate — κλήση super.onCreate(savedInstanceState) και setContentView(R.layout.activity_main).
class MainActivity : AppCompatActivity() {
private var binding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ViewBinding — σύγχρονη αντικατάσταση του findViewById
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding?.root)
// Αρχικοποίηση με χρήση binding
binding?.apply {
welcomeText.text = getString(R.string.welcome)
startButton.setOnClickListener { startGame() }
}
// Επαναφορά κατάστασης
if (savedInstanceState != null) {
score = savedInstanceState.getInt("score", 0)
binding?.scoreText?.text = score.toString()
}
}
}
Σύγχρονη πρακτική — χρήση ViewBinding αντί για findViewById. Το ViewBinding δημιουργεί την κλάση ActivityMainBinding στο στάδιο μεταγλώττισης, εξαλείφοντας σφάλματα με λανθασμένα ID και μειώνοντας τον όγκο του κώδικα πρότυπου. Η Google συνιστά το ViewBinding ως τον τυπικό τρόπο πρόσβασης στο View σε Activity και Fragment από το Android Studio 3.6.
Η σειρά ενεργειών στο onCreate πρέπει να είναι αυστηρή: πρώτα super, μετά setContentView, έπειτα όλα τα υπόλοιπα. Η κλήση findViewById πριν από το setContentView επιστρέφει null — η διάταξη δεν έχει ακόμη φορτωθεί και τα στοιχεία View δεν υπάρχουν στην ιεραρχία. Αυτό είναι ένα από τα πιο συνηθισμένα λάθη αρχάριων προγραμματιστών Android.
Το onCreate στο Fragment διαφέρει από το Activity: εδώ δεν καλείται setContentView, εκτελείται μόνο αρχικοποίηση δεδομένων που δεν σχετίζονται με UI. Το Fragment διαχωρίζει τη δημιουργία του component και τη δημιουργία View σε δύο ξεχωριστές μεθόδους: onCreate (καλείται μία φορά) και onCreateView (καλείται κάθε φορά κατά τη δημιουργία ή αναδημιουργία του View).
class UserListFragment : Fragment() {
private lateinit var viewModel: UserViewModel
private var binding: FragmentUserListBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Αρχικοποίηση ViewModel — θα επιβιώσει από την αναδημιουργία View
viewModel = ViewModelProvider(this)[UserViewModel::class.java]
// Ορίσματα από FragmentManager
arguments?.let {
viewModel.loadUser(it.getString("user_id") ?: "")
}
// Αποθήκευση κατά την περιστροφή
retainInstance = true
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentUserListBinding.inflate(inflater, container, false)
return binding!!.root
}
}
Η βασική διαφορά μεταξύ onCreate Activity και Fragment: το onCreate στο Fragment δεν πρέπει να περιέχει κώδικα που σχετίζεται με View, επειδή το View μπορεί να καταστραφεί και να δημιουργηθεί ξανά (για παράδειγμα, κατά την εναλλαγή καρτελών ViewPager), ενώ το onCreate καλείται μόνο μία φορά. Φόρτωση δεδομένων, ρύθμιση ViewModel και αρχικοποίηση προσαρμογέων — εργασίες του onCreate, ενώ η σύνδεση View — εργασία του onViewCreated.
Η παράμετρος savedInstanceState στο onCreate — είναι ο μηχανισμός αποθήκευσης και επαναφοράς της προσωρινής κατάστασης Activity ή Fragment. Όταν το σύστημα καταστρέφει το Activity (περιστροφή οθόνης, έλλειψη μνήμης), καλεί onSaveInstanceState(), στο οποίο ο προγραμματιστής τοποθετεί ένα ζεύγος κλειδιού-τιμής στο Bundle. Κατά τη δημιουργία νέας παρουσίας, αυτό το Bundle επιστρέφεται στο onCreate.
Το Bundle υποστηρίζει τους ακόλουθους τύπους δεδομένων: String, Integer, Boolean, Long, Float, Double, τους πίνακές τους, καθώς και αντικείμενα Parcelable και Serializable. Για σύνθετα αντικείμενα χρησιμοποιείται Parcelable — ένας πιο αποδοτικός μηχανισμός σειριοποίησης, ειδικός για Android. Το μέγεθος του Bundle περιορίζεται σε περίπου 500 KB — η υπέρβαση του ορίου προκαλεί εξαίρεση TransactionTooLargeException.
companion object {
private const val KEY_USER_NAME = "user_name"
private const val KEY_SCORE = "score"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_game)
if (savedInstanceState != null) {
userName = savedInstanceState.getString(KEY_USER_NAME) ?: ""
currentScore = savedInstanceState.getInt(KEY_SCORE)
}
}
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putString(KEY_USER_NAME, userName)
outState.putInt(KEY_SCORE, currentScore)
}
Είναι σημαντικό να κατανοήσετε: το onSaveInstanceState δεν καλείται όταν ο χρήστης κλείνει ρητά το Activity μέσω finish() ή πατώντας το κουμπί «Πίσω». Το σύστημα θεωρεί ότι σε αυτήν την περίπτωση ο χρήστης συνειδητά τερματίζει την εργασία και η αποθήκευση κατάστασης δεν απαιτείται. Επομένως, δεν πρέπει να βασίζεστε αποκλειστικά στο savedInstanceState για μακροπρόθεσμη αποθήκευση δεδομένων — χρησιμοποιήστε Room, DataStore ή SharedPreferences.
Το onCreate εκτελείται στο κύριο (UI) νήμα και το σύστημα περιμένει την ολοκλήρωσή του πριν εμφανίσει το Activity στην οθόνη. Αν το onCreate διαρκέσει περισσότερο από 5 δευτερόλεπτα, το σύστημα εμφανίζει ένα παράθυρο διαλόγου ANR (Application Not Responding) και προτείνει στον χρήστη να κλείσει την εφαρμογή. Οι μακροχρόνιες λειτουργίες, όπως η φόρτωση δεδομένων από το δίκτυο ή η ανάγνωση από τη βάση δεδομένων, πρέπει να μεταφέρονται σε νήμα παρασκηνίου.
Σύμφωνα με τις συστάσεις Google Android Performance (2025), το onCreate πρέπει να ολοκληρώνεται σε λιγότερο από 1 δευτερόλεπτο σε συσκευές μεσαίου τμήματος. Για αυτό, πρέπει: να χρησιμοποιείτε τεμπέλικη αρχικοποίηση (lazy delegate σε Kotlin), να αναβάλλετε τη φόρτωση βαρέων δεδομένων στο onResume ή μέσω coroutine, να εφαρμόζετε ViewStub για σπάνια χρησιμοποιούμενα component UI, να προφιλάρετε τον χρόνο εκκίνησης μέσω Android Vitals.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Τεμπέλικη αρχικοποίηση — το αντικείμενο δημιουργείται μόνο στην πρώτη πρόσβαση
val heavyData by lazy {
HeavyDataLoader.load()
}
// Φόρτωση δεδομένων σε νήμα παρασκηνίου μέσω lifecycleScope
lifecycleScope.launch(Dispatchers.IO) {
val users = userDao.getAllUsers()
withContext(Dispatchers.Main) {
adapter.submitList(users)
}
}
}
Εργαλεία προφίλ: το Android Studio Profiler (καρτέλα CPU) δείχνει τον ακριβή χρόνο εκτέλεσης κάθε μεθόδου. Στο Android Vitals (κονσόλα Google Play) μπορείτε να παρακολουθείτε τη μετρική «Χρόνος ψυχρής εκκίνησης» — αν το onCreate του Activity σας υπερβαίνει τα 500 ms, η κονσόλα το επισημαίνει ως πρόβλημα απόδοσης. Εμείς στην IT Sectr χρησιμοποιούμε δοκιμές Macrobenchmark για αυτόματο έλεγχο του χρόνου εκκίνησης κάθε Activity στο pipeline CI.
ViewModel — ο καλύτερος τρόπος αρχικοποίησης δεδομένων στο onCreate που πρέπει να επιβιώσουν από την περιστροφή οθόνης. Το ViewModel δημιουργείται στο onCreate μέσω ViewModelProvider και αποθηκεύεται αυτόματα κατά την αλλαγή διαμόρφωσης. Όταν το Activity αναδημιουργείται μετά από περιστροφή, το ViewModel παραμένει στη μνήμη και το onCreate λαμβάνει το ίδιο ViewModel χωρίς απώλεια δεδομένων.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_profile)
// Το ViewModel δημιουργείται μία φορά και επιβιώνει από αλλαγές διαμόρφωσης
val viewModel: ProfileViewModel =
ViewModelProvider(this)[ProfileViewModel::class.java]
// Παρατήρηση LiveData — το UI ενημερώνεται αυτόματα όταν αλλάζουν τα δεδομένα
viewModel.user.observe(this) { user ->
binding?.userName?.text = user.name
binding?.userEmail?.text = user.email
}
// Φόρτωση δεδομένων αν το ViewModel μόλις δημιουργήθηκε
if (savedInstanceState == null) {
viewModel.loadProfile(userId)
}
}
Ο συνδυασμός ViewModel + LiveData/StateFlow λύνει το πρόβλημα της περιστροφής οθόνης χωρίς χειροκίνητη αποθήκευση στο Bundle. Το ViewModel αποθηκεύει δεδομένα στη μνήμη, το LiveData αυτόματα επανεγγράφει το Activity κατά την αναδημιουργία και το StateFlow (από Kotlin Coroutines) προσθέτει αντιδραστικότητα με υποστήριξη coroutine. Αυτή είναι η τυπική αρχιτεκτονική που συνιστά η Google στον οδηγό Guide to App Architecture.
Ακόμη και έμπειροι προγραμματιστές κάνουν τυπικά λάθη στο onCreate. Ας εξετάσουμε πέντε από τα πιο συνηθισμένα προβλήματα και τρόπους αποφυγής τους.
Το πιο συνηθισμένο λάθος — προσπάθεια εύρεσης View μέσω findViewById πριν από την κλήση setContentView. Όλα τα στοιχεία View δημιουργούνται τη στιγμή της διόγκωσης της διάταξης, επομένως οποιαδήποτε αναφορά σε findViewById πριν από setContentView επιστρέφει null και προκαλεί NullPointerException κατά την προσπάθεια χρήσης View. Λύση: αυστηρή σειρά — πρώτα super, μετά setContentView, έπειτα findViewById ή ViewBinding.
Η φόρτωση δεδομένων από το δίκτυο, η ανάγνωση από τη βάση δεδομένων ή η επεξεργασία μεγάλων πινάκων απευθείας στο onCreate μπλοκάρει την απόδοση του πρώτου καρέ. Ο χρήστης βλέπει μια μαύρη οθόνη μέχρι να ολοκληρωθεί το onCreate, γεγονός που υποβαθμίζει την αντίληψη της ταχύτητας της εφαρμογής. Λύση: χρησιμοποιήστε lifecycleScope.launch για ασύγχρονες λειτουργίες, εμφανίστε έναν σκελετό (placeholder UI) μέχρι να ολοκληρωθεί η φόρτωση.
Αν κατά την περιστροφή οθόνης δεν επαναφέρεται η κατάσταση από το Bundle, ο χρήστης χάνει όλη τη μη αποθηκευμένη είσοδο: κείμενο σε πεδία φόρμας, θέση κύλισης, επιλεγμένα στοιχεία. Λύση: ελέγχετε πάντα savedInstanceState != null στο onCreate για επαναφορά δεδομένων, ακόμη κι αν η απώλεια κατάστασης φαίνεται απίθανη.
Οι ανώνυμες κλάσεις και τα lambda στο onCreate μπορούν σιωπηρά να διατηρήσουν αναφορά στο Activity μετά την καταστροφή του. Για παράδειγμα, ένα Handler που δημιουργήθηκε στο onCreate συνεχίζει να εκτελεί καθυστερημένες εργασίες ακόμη και μετά την καταστροφή του Activity. Λύση: χρησιμοποιήστε LifecycleObserver, ViewModel και lifecycleScope, που ακυρώνουν αυτόματα εργασίες κατά την καταστροφή.
Η αρχικοποίηση View στο onCreate Fragment — λογικό λάθος, επειδή το View μπορεί να αναδημιουργηθεί χωρίς κλήση του onCreate. Αν οριστεί ένας ακροατής στο onCreate και το View συνδεθεί στο onCreateView, κατά την αναδημιουργία ο ακροατής παραμένει στο παλιό View. Λύση: όλη η εργασία με View εκτελείται στο onViewCreated, και το onCreate αφήνεται μόνο για αρχικοποίηση του επιπέδου δεδομένων.
Συχνές ερωτήσεις
Ναι, η παράκαμψη του onCreate είναι υποχρεωτική για κάθε Activity που εμφανίζει διεπαφή χρήστη. Χωρίς αυτήν, δεν μπορεί να κληθεί setContentView και να φορτωθεί η διάταξη XML. Αν το Activity δεν έχει UI (για παράδειγμα, ένα διαφανές Activity-υποκατάστατο), το onCreate παρακάμπτεται ωστόσο, αλλά χωρίς κλήση setContentView.
Όχι, το onCreate δεν μπορεί να κληθεί ξανά για την ίδια παρουσία Activity. Αν το Activity καταστραφεί και δημιουργηθεί ξανά (περιστροφή οθόνης, έλλειψη μνήμης), αυτή είναι ήδη μια νέα παρουσία με νέα κλήση onCreate. Εξαίρεση — η μέθοδος recreate(), που αναγκάζει την καταστροφή και αναδημιουργία του Activity, αλλά αυτό είναι αναδημιουργία νέας παρουσίας.
Αν δεν κληθεί το super.onCreate(savedInstanceState), το Android Runtime θα πετάξει εξαίρεση SuperNotCalledException και η εφαρμογή θα καταρρεύσει. Το σύστημα απαιτεί αυστηρά κάθε παρακαμφθείσα μέθοδος κύκλου ζωής να καλεί την super έκδοσή της — αυτό εγγυάται τη σωστή λειτουργία της εσωτερικής μηχανής καταστάσεων.
Η βασική διαφορά: το onCreate στο Activity φορτώνει UI μέσω setContentView, ενώ το onCreate στο Fragment μόνο αρχικοποιεί δεδομένα. Το Fragment δημιουργεί View στην ξεχωριστή μέθοδο onCreateView, που μπορεί να κληθεί πολλές φορές (για παράδειγμα, κατά την εναλλαγή καρτελών), ενώ το onCreate του Fragment καλείται μία φορά κατά τη διάρκεια ζωής της παρουσίας Fragment.
Τα δεδομένα που αρχικοποιούνται στο onCreate αποθηκεύονται στα πεδία της κλάσης Activity ή Fragment. Για παράδειγμα, το private lateinit var binding: ActivityMainBinding δηλώνεται σε επίπεδο κλάσης, αρχικοποιείται στο onCreate και είναι προσβάσιμο σε όλες τις επόμενες μεθόδους. Για δεδομένα που επιβιώνουν από περιστροφή οθόνης, χρησιμοποιήστε ViewModel με LiveData ή StateFlow.
Περίληψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης