Fragment Lifecycle: βασικές αρχές, μέθοδοι onCreateView onViewCreated

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

Fragment Lifecycle — μια αυστηρά καθορισμένη ακολουθία μεθόδων callback που καλεί το Android κατά τη διάρκεια ζωής ενός Fragment: από τη δημιουργία (onAttach) έως την πλήρη αφαίρεση (onDetach). Το Fragment έχει πιο σύνθετο κύκλο ζωής από το Activity — περιλαμβάνει 11 καταστάσεις και 7 βασικά callback. Το Fragment Lifecycle διαχειρίζεται μέσω του FragmentManager και συνδέεται στενά με τον κύκλο ζωής του Activity που το περιέχει. Σύμφωνα με τα δεδομένα της Google, το Fragment χρησιμοποιείται στο 74% των εφαρμογών Android που λειτουργούν σε API Level 21+, καθιστώντας την κατανόηση του Fragment Lifecycle υποχρεωτική για επαγγελματική ανάπτυξη Android. Η τεκμηρίωση Android για το Fragment Lifecycle περιγράφει όλες τις καταστάσεις και τις εγγυήσεις κλήσης.

Κύρια σημεία

  • Fragment Lifecycle περιλαμβάνει 7 callback: onAttach, onCreate, onCreateView, onViewCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach.
  • Το FragmentManager διαχειρίζεται τις καταστάσεις του Fragment και εγγυάται τη σωστή σειρά κλήσεων στις συναλλαγές.
  • Τα onCreateView και onViewCreated — βασικές μέθοδοι για τη δημιουργία και διαμόρφωση του UI του Fragment.
  • Το Fragment μπορεί να επιβιώσει από το Activity του (κατά την περιστροφή οθόνης) και να επαναφέρει την κατάσταση μέσω onSaveInstanceState.
  • viewLifecycleOwner — ξεχωριστός Lifecycle για το View του Fragment, καταστρέφεται στο onDestroyView.

Fragment Lifecycle: βασικές αρχές κύκλου ζωής

Fragment Lifecycle είναι ένα σύνολο αλληλένδετων καταστάσεων και μεθόδων από τις οποίες περνά κάθε στιγμιότυπο Fragment από τη στιγμή της δημιουργίας έως την καταστροφή. Σε αντίθεση με το Activity, ο κύκλος ζωής του Fragment συνδέεται με δύο περιβάλλοντα: το ίδιο το Fragment (ζει από onAttach έως onDetach) και το View του (ζει από onCreateView έως onDestroyView). Αυτός ο διαχωρισμός είναι ένα βασικό χαρακτηριστικό του Fragment, που του επιτρέπει να επιβιώνει από την καταστροφή του View κατά την περιστροφή οθόνης χωρίς να καταστρέφεται το ίδιο το Fragment.

Πλήρης ακολουθία callback του Fragment:

  • onAttach(Context) — Το Fragment προσδένεται στο Activity. Καλείται πρώτο. Context — Activity-οικοδεσπότης.
  • onCreate(Bundle) — Το Fragment αρχικοποιείται. Εδώ δημιουργούνται ViewModel, ρυθμίζονται προσαρμογείς.
  • onCreateView(LayoutInflater, ViewGroup, Bundle) — δημιουργείται η ιεραρχία View του Fragment. Επιστρέφει το ριζικό View.
  • onViewCreated(View, Bundle) — Το View δημιουργήθηκε. Εδώ ρυθμίζονται στοιχεία UI, εγγραφές LiveData.
  • onStart() — Το Fragment είναι ορατό. Ξεκινούν κινούμενα σχέδια, καταγράφονται αισθητήρες.
  • onResume() — Το Fragment είναι ενεργό, αλληλεπιδρά με τον χρήστη.
  • onPause() — Το Fragment χάνει εστίαση. Σταματούν τα κινούμενα σχέδια.
  • onStop() — Το Fragment είναι αόρατο. Απελευθερώνονται μη κρίσιμοι πόροι.
  • onDestroyView() — η ιεραρχία View καταστρέφεται. Οι αναφορές στο View μηδενίζονται.
  • onDestroy() — Το Fragment καταστρέφεται. Ακυρώνονται coroutine εκτός viewModelScope.
  • onDetach() — Το Fragment αποσυνδέεται από το Activity. Τελικός καθαρισμός.

Σύμφωνα με την Google, το μέσο fragment σε μια σύγχρονη εφαρμογή περνά τον πλήρη κύκλο 3–5 φορές ανά συνεδρία χρήστη (λόγω περιστροφών οθόνης και πλοήγησης). Η σωστή διαχείριση όλων των φάσεων είναι η βάση της σταθερότητας του UI.

Καταστάσεις Fragment: από INITIALIZED έως DESTROYED

Το FragmentManager διαχειρίζεται το Fragment μέσω πέντε βασικών καταστάσεων, που ορίζονται στην κλάση Fragment.State. Κάθε κατάσταση αντιστοιχεί σε ένα συγκεκριμένο σύνολο callback που έχουν εκτελεστεί.

ΚατάστασηΣημασίαΕκτελεσμένα callback
INITIALIZEDFragment δημιουργήθηκε, αλλά View δεν υπάρχει ακόμαonAttach, onCreate
CREATEDView δημιουργήθηκε, αλλά Fragment δεν είναι ορατό+ onCreateView, onViewCreated
STARTEDFragment ορατό, αλλά μη ενεργό+ onStart
RESUMEDFragment ενεργό, αλληλεπιδρά με τον χρήστη+ onResume
DESTROYEDFragment καταστράφηκε+ onDestroyView, onDestroy, onDetach

Το FragmentManager μετακινεί το Fragment μεταξύ καταστάσεων ανάλογα με τις ενέργειες του χρήστη και τα συμβάντα συστήματος. Κατά την προσθήκη του Fragment σε ένα δοχείο, περνά διαδοχικά από INITIALIZED → CREATED → STARTED → RESUMED. Κατά την αφαίρεση — RESUMED → STARTED → CREATED → DESTROYED.

Η κατάσταση CREATED — ειδική: το View μπορεί να καταστραφεί (μετά το onDestroyView), αλλά το ίδιο το Fragment παραμένει στην κατάσταση CREATED (μετά το onDestroyView, πριν το onDestroy). Αυτό επιτρέπει στο FragmentManager να διατηρεί το Fragment στη μνήμη χωρίς View, το οποίο είναι απαραίτητο για την επιβίωση των περιστροφών οθόνης.

Διαφορά μεταξύ Fragment Lifecycle και Activity Lifecycle

Το Fragment Lifecycle και το Activity Lifecycle συνδέονται στενά, αλλά έχουν θεμελιώδεις διαφορές. Το Fragment ζει πάντα μέσα σε ένα Activity και ο κύκλος ζωής του εξαρτάται από το Activity-οικοδεσπότη, αλλά δεν είναι ταυτόσημος με αυτό.

ΠτυχήActivityFragment
Αριθμός callback7 (onCreate … onDestroy)11 (onAttach … onDetach)
Ξεχωριστός Lifecycle για ViewΌχιΝαι (viewLifecycleOwner)
Επιβιώνει περιστροφήΌχι (καταστρέφεται)Ναι (ViewModel + Fragment επιβιώνουν)
Εξάρτηση από οικοδεσπότηΌχιΕξαρτάται από Activity Lifecycle
Αποθήκευση κατάστασηςonSaveInstanceStateonSaveInstanceState (fragment)
ΔιαχείρισηΣύστημαFragmentManager

Κύρια πρακτική διαφορά: κατά την περιστροφή οθόνης, το Activity καταστρέφεται πλήρως (onDestroy) και δημιουργείται ξανά (onCreate). Το Fragment κατά την περιστροφή περνά από onDestroyView (το View καταστρέφεται) → onCreateView (το View δημιουργείται ξανά), αλλά το ίδιο το Fragment και το ViewModel του παραμένουν ζωντανά. Αυτό καθιστά το Fragment ιδανικό δοχείο για λογική UI που πρέπει να επιβιώνει από αλλαγές διαμόρφωσης.

Σειρά κλήσεων κατά την περιστροφή οθόνης: Activity.onPause → Fragment.onPause → Activity.onStop → Fragment.onStop → Activity.onDestroy → Fragment.onDestroyView → (Activity καταστράφηκε) → Activity.onCreate → Fragment.onAttach → Fragment.onCreate → Fragment.onCreateView → Fragment.onViewCreated → Activity.onStart → Fragment.onStart → Activity.onResume → Fragment.onResume.

FragmentManager: διαχείριση καταστάσεων και συναλλαγών

FragmentManager — η κεντρική κλάση υπεύθυνη για την προσθήκη, αφαίρεση, αντικατάσταση fragment και διαχείριση των καταστάσεών τους. Το FragmentManager διατηρεί τη στοίβα BackStack και εγγυάται τη σωστή σειρά callback στις συναλλαγές. Κάθε Activity και κάθε ένθετο Fragment έχει το δικό του FragmentManager.

Κύριες λειτουργίες του FragmentManager:

  • beginTransaction() — ανοίγει μια συναλλαγή για μια ομάδα λειτουργιών.
  • add() — προσθέτει Fragment σε ένα δοχείο. Το Fragment περνά πλήρη lifecycle έως RESUMED.
  • replace() — αντικαθιστά το τρέχον Fragment με ένα νέο. ισούται με remove() + add().
  • remove() — αφαιρεί το Fragment. Το Fragment περνά lifecycle από RESUMED έως DESTROYED.
  • hide()/show() — κρύβει/εμφανίζει το Fragment χωρίς να καταστρέφει το View. Το Fragment πηγαίνει σε STARTED στο hide, πίσω σε RESUMED στο show.
  • detach()/attach() — αποσπά/προσαρτά το Fragment. detach καταστρέφει το View (onDestroyView), attach το δημιουργεί ξανά (onCreateView).
  • addToBackStack() — προσθέτει συναλλαγή στο BackStack για δυνατότητα πλοήγησης “Πίσω”.

BackStack — στοίβα συναλλαγών του FragmentManager. Όταν πατηθεί το κουμπί συστήματος “Πίσω”, η τελευταία συναλλαγή στο BackStack αναιρείται (popBackStack()). Το Fragment που αφαιρέθηκε μέσω popBackStack αποκαθίσταται. Εάν το BackStack είναι άδειο, το πάτημα “Πίσω” τερματίζει το Activity.

Σύμφωνα με την Google, 78% των προβλημάτων με Fragment (διπλασιασμός, κενές οθόνες, IllegalStateException) σχετίζονται με λανθασμένη χρήση του FragmentManager. Κύριος κανόνας: εκτελείτε συναλλαγές μέσω commit() (ασύγχρονα) ή commitNow() (σύγχρονα) ανάλογα με το περιβάλλον. Το commit() εγγυάται τη σωστή σειρά σε πολλαπλές συναλλαγές.

Αποθήκευση κατάστασης Fragment: onSaveInstanceState

Το Fragment υποστηρίζει τον δικό του μηχανισμό αποθήκευσης κατάστασης μέσω onSaveInstanceState, ο οποίος λειτουργεί ανεξάρτητα από το Activity. Το Fragment αποθηκεύει κατάσταση στο Bundle, το οποίο μεταβιβάζεται στα onCreate και onCreateView κατά την επαναφορά.

Πότε το Fragment αποθηκεύει κατάσταση:

  • Κατά την περιστροφή οθόνης — το View καταστρέφεται, το Fragment αποθηκεύει κατάσταση στο Bundle.
  • Κατά την προσάρτηση του Fragment στο Activity μετά από process death.
  • Κατά την κλήση onSaveInstanceState από το Activity (το σύστημα διαδίδει την αποθήκευση σε όλα τα θυγατρικά fragment).

Σύγχρονη προσέγγιση: χρησιμοποιήστε SavedStateHandle στο ViewModel για αποθήκευση κατάστασης Fragment. Το SavedStateHandle αποθηκεύει και επαναφέρει αυτόματα δεδομένα κατά την περιστροφή οθόνης και process death, χωρίς να απαιτεί χειροκίνητο onSaveInstanceState. Η Google συνιστά το SavedStateHandle ως προτιμώμενο τρόπο αποθήκευσης κατάστασης UI στο Fragment.

setRetainInstance (ξεπερασμένο από Fragment 1.3): προηγουμένως το Fragment μπορούσε να διατηρηθεί μέσω setRetainInstance(true) κατά την περιστροφή οθόνης. Αυτή η προσέγγιση αντικαταστάθηκε από ViewModel + SavedStateHandle, που λειτουργούν πιο αξιόπιστα και δεν απαιτούν ειδική διαμόρφωση.

viewLifecycleOwner: ξεχωριστός κύκλος ζωής View

viewLifecycleOwner — Lifecycle συνδεδεμένο με το View του Fragment (από onCreateView έως onDestroyView). Αυτή είναι μια θεμελιωδώς σημαντική έννοια: οι εγγραφές LiveData/Flow που γίνονται μέσω viewLifecycleOwner ακυρώνονται αυτόματα κατά την καταστροφή του View (onDestroyView), αλλά δεν επηρεάζουν το ίδιο το Fragment.

Διαφορά μεταξύ viewLifecycleOwner και lifecycle του Fragment:

  • lifecycle (Fragment) — ζει από onAttach έως onDetach. Οι εγγραφές παραμένουν ενεργές ακόμη και μετά την καταστροφή του View.
  • viewLifecycleOwner — ζει από onCreateView έως onDestroyView. Οι εγγραφές ακυρώνονται κατά την καταστροφή του View.

Γιατί είναι σημαντικό: αν εγγραφείτε στο LiveData μέσω του lifecycle του Fragment (this), μετά το onDestroyView η εγγραφή παραμένει ενεργή και το LiveData θα προσπαθήσει να ενημερώσει το null View, προκαλώντας NPE. Η εγγραφή μέσω viewLifecycleOwner εγγυάται ότι μετά το onDestroyView δεν θα γίνουν ενημερώσεις UI.

Κανόνας: στο Fragment, χρησιμοποιείτε πάντα viewLifecycleOwner για εγγραφές LiveData, Flow και coroutine που σχετίζονται με το UI. Για coroutine ViewModel, χρησιμοποιείτε viewModelScope — αυτό συνδέεται με το ViewModel, όχι με το Fragment.

Παραδείγματα κώδικα Fragment σε Kotlin

Παράδειγμα 1: Βασικό Fragment με onViewCreated και viewLifecycleOwner

Δείχνει σωστή αρχικοποίηση UI και εγγραφή LiveData μέσω viewLifecycleOwner.

kotlin
class UserListFragment : Fragment() {
    private val viewModel: UserListViewModel by viewModels()

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        return inflater.inflate(R.layout.fragment_user_list, container, false)
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val button: Button = view.findViewById(R.id.load_button)
        button.setOnClickListener { viewModel.loadUsers() }
        viewModel.users.observe(viewLifecycleOwner) { users ->
            Log.d("UserListFragment", "Ενημέρωση λίστας: ${users.size} χρήστες")
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        Log.d("UserListFragment", "onDestroyView: View καταστράφηκε")
    }
}

Το Fragment φουσκώνει το layout στο onCreateView, ρυθμίζει το UI και εγγράφεται στο LiveData στο onViewCreated. Η εγγραφή μέσω viewLifecycleOwner — υποχρεωτική απαίτηση για την πρόληψη διαρροών μνήμης. Το onDestroyView καταγράφει την καταστροφή του View — επιβεβαίωση ότι το Fragment επιβιώνει από την περιστροφή οθόνης.

Παράδειγμα 2: Fragment με FragmentManager και συναλλαγές

Δείχνει προσθήκη Fragment μέσω FragmentManager στο Activity, αντικατάσταση με BackStack και επαναφορά.

kotlin
class HostActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_host)
        if (savedInstanceState == null) {
            supportFragmentManager.beginTransaction()
                .add(R.id.fragment_container, HomeFragment())
                .addToBackStack(null)
                .commit()
        }
    }

    fun openDetail(userId: String) {
        supportFragmentManager.beginTransaction()
            .replace(R.id.fragment_container, DetailFragment.newInstance(userId))
            .addToBackStack(null)
            .commit()
    }

    override fun onBackPressed() {
        if (supportFragmentManager.backStackEntryCount > 0) {
            supportFragmentManager.popBackStack()
        } else {
            super.onBackPressed()
        }
    }
}

class DetailFragment : Fragment() {
    companion object {
        fun newInstance(userId: String): DetailFragment {
            return DetailFragment().apply {
                arguments = Bundle().apply { putString("user_id", userId) }
            }
        }
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val userId = arguments?.getString("user_id")
        Log.d("DetailFragment", "Φόρτωση λεπτομερειών χρήστη: $userId")
    }
}

Το Activity χρησιμοποιεί supportFragmentManager για τη διαχείριση fragment. Η συναλλαγή add() με BackStack εγγυάται ότι όταν πατηθεί “Πίσω” το HomeFragment θα αποκατασταθεί. Η openDetail() αντικαθιστά το τρέχον Fragment με DetailFragment με ορίσματα. Ο έλεγχος savedInstanceState == null αποτρέπει τον διπλασιασμό fragment κατά την περιστροφή οθόνης.

Παράδειγμα 3: Fragment με LifecycleObserver και StateFlow

Χρήση Flow και StateFlow σε Fragment με viewLifecycleOwner για αντιδραστική ενημέρωση UI.

kotlin
class SearchFragment : Fragment() {
    private val viewModel: SearchViewModel by viewModels()
    private var binding: FragmentSearchBinding? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentSearchBinding.inflate(inflater, container, false)
        return binding!!.root
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        binding?.searchButton?.setOnClickListener {
            viewModel.search(binding?.queryInput?.text.toString())
        }
        viewLifecycleOwner.lifecycleScope.launch {
            viewModel.searchResults.collectLatest { results ->
                Log.d("SearchFragment", "Αποτελέσματα αναζήτησης: ${results.size}")
            }
        }
    }

    override fun onDestroyView() {
        super.onDestroyView()
        binding = null
    }
}

Το Fragment χρησιμοποιεί View Binding για πρόσβαση στο View. Το coroutine viewLifecycleOwner.lifecycleScope.launch ακυρώνεται αυτόματα κατά την καταστροφή του View. Το Binding μηδενίζεται στο onDestroyView για πρόληψη διαρροών μνήμης. Το StateFlow εγγυάται την επικαιρότητα των δεδομένων κατά την αναδημιουργία του View.

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

Σε τι διαφέρει το onViewCreated από το onCreateView;

onCreateView — δημιουργεί και επιστρέφει το ριζικό View του Fragment. onViewCreated — καλείται αμέσως μετά τη δημιουργία του View, εγγυάται ότι το View είναι πλήρως αρχικοποιημένο και έτοιμο για ρύθμιση (findViewById, εγγραφές). Η Google συνιστά στο onCreateView να φουσκώνετε μόνο το layout, και όλη τη ρύθμιση UI να την κάνετε στο onViewCreated.

Πότε καταστρέφεται πραγματικά το Fragment — onDestroy ή onDetach;

onDestroy — το Fragment καταστράφηκε ως αντικείμενο (ViewModel καθαρίζεται, coroutine ακυρώνονται). onDetach — το τελευταίο callback, μετά το οποίο το Fragment αποσυνδέεται από το Activity. Πρακτικά όλοι οι πόροι πρέπει να απελευθερωθούν στο onDestroyView (View) και onDestroy (Fragment). onDetach — για καθαρισμό αναφορών στο Activity.

Γιατί εξαφανίζεται το Fragment μετά την περιστροφή οθόνης;

Το Fragment εξαφανίζεται αν δεν προστέθηκε στο FragmentManager μέσω συναλλαγής με αποθήκευση στο BackStack ή αν το Activity δεν επαναφέρει το FragmentManager στο onCreate. Λύση: προσθέστε το Fragment προγραμματιστικά μέσω supportFragmentManager.beginTransaction().add() στο onCreate με έλεγχο savedInstanceState == null.

Μπορεί ένα Fragment να υπάρξει χωρίς Activity;

Όχι. Το Fragment είναι πάντα συνδεδεμένο με ένα Activity μέσω του FragmentManager. Ακόμη και κατά την περιστροφή οθόνης, το Activity αναδημιουργείται και το Fragment επανασυνδέεται στο νέο Activity. Η δημιουργία Fragment εκτός Activity είναι αδύνατη — ο κατασκευαστής του Fragment απαιτεί κενό κατασκευαστή για επαναφορά από το σύστημα.

Τι είναι τα nested fragments και σε τι χρησιμεύουν;

Nested fragments (ένθετα fragment) — Fragment μέσα σε άλλο Fragment. Χρησιμοποιούνται για τη δημιουργία σύνθετων οθονών: πίνακες καρτελών, πίνακες με καρτέλες, master-detail. Τα ένθετα fragment διαχειρίζονται από το θυγατρικό FragmentManager (childFragmentManager). Η Google συνιστά να μην υπερβαίνετε τα 2 επίπεδα ένθεσης για αποφυγή προβλημάτων απόδοσης.

Σύνοψη

  • Fragment Lifecycle περιλαμβάνει 11 callback: onAttach → onCreate → onCreateView → onViewCreated → onStart → onResume → onPause → onStop → onDestroyView → onDestroy → onDetach.
  • Το FragmentManager διαχειρίζεται καταστάσεις Fragment (INITIALIZED → CREATED → STARTED → RESUMED → DESTROYED) και BackStack συναλλαγών.
  • Το Fragment επιβιώνει από περιστροφή οθόνης — το View καταστρέφεται (onDestroyView), αλλά το Fragment και το ViewModel παραμένουν ζωντανά.
  • viewLifecycleOwner — ξεχωριστός Lifecycle για το View του Fragment, υποχρεωτικός για εγγραφές LiveData και UI coroutine.
  • Αποθήκευση κατάστασης Fragment — μέσω onSaveInstanceState ή SavedStateHandle στο ViewModel.
  • Οι συναλλαγές Fragment εκτελούνται μέσω FragmentManager με commit() (ασύγχρονα) ή commitNow() (σύγχρονα).
  • Πάντα μηδενίζετε το binding και τις αναφορές στο View στο onDestroyView για πρόληψη διαρροών μνήμης.

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

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

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

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