StatefulWidget: τι είναι, κύκλος ζωής και αρχή λειτουργίας

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

StatefulWidget — ένα widget Flutter με μεταβλητή κατάσταση, που επιτρέπει στο UI να αντιδρά σε ενέργειες χρήστη, ασύγχρονα συμβάντα και ροές δεδομένων. Σύμφωνα με την επίσημη τεκμηρίωση Flutter (Flutter.dev, 2026), το StatefulWidget χρησιμοποιείται για όλα τα διαδραστικά στοιχεία της εφαρμογής: φόρμες εισαγωγής, κινητικά, πεδία επιλογής, διακόπτες και οθόνες που φορτώνουν δεδομένα από το δίκτυο. Σε αντίθεση με το StatelessWidget, δημιουργεί ένα ξεχωριστό αντικείμενο State που διατηρείται σε όλο τον κύκλο ζωής και μπορεί να ανακατασκευαστεί χωρίς να επαναδημιουργηθεί το ίδιο το widget.

Κύρια σημεία

  • StatefulWidget — ένα widget που μπορεί να αλλάξει την κατάστασή του κατά τη λειτουργία, προκαλώντας την ανακατασκευή του UI μέσω setState
  • Κύκλος ζωής — το StatefulWidget διέρχεται από τα στάδια createState, initState, didChangeDependencies, build, didUpdateWidget, dispose
  • Αντικείμενο State — ένα ξεχωριστό αντικείμενο που αποθηκεύει την κατάσταση και υπάρχει ανεξάρτητα από το widget σε όλη τη διάρκεια της ζωής του
  • setState — ο μόνος νόμιμος τρόπος ειδοποίησης του Flutter για την ανάγκη ανακατασκευής του widget μετά από αλλαγή δεδομένων
  • Απόδοση — η υπερβολική χρήση του StatefulWidget αυξάνει την κατανάλωση μνήμης και τον χρόνο απόδοσης

Τι είναι το StatefulWidget;

StatefulWidget — είναι μια κλάση Flutter που μπορεί να αλλάξει την κατάστασή της ως απάντηση σε ενέργειες χρήστη, συστημικά συμβάντα ή ασύγχρονες λειτουργίες. Σε αντίθεση με το StatelessWidget, το StatefulWidget δεν εμφανίζεται άμεσα — δημιουργεί ένα αντικείμενο State που είναι υπεύθυνο για την απόδοση. Η διαίρεση σε δύο κλάσεις (Widget και State) επιτρέπει στο Flutter να ανακατασκευάζει το UI χωρίς να επαναδημιουργεί το ίδιο το widget, πράγμα που παρέχει σημαντικό πλεονέκτημα απόδοσης σε συχνές ενημερώσεις.

Η αρχιτεκτονική του StatefulWidget ακολουθεί το μοτίβο «διαχωρισμός μεταβλητού και αμετάβλητου»: το ίδιο το widget παραμένει αμετάβλητο (όπως το StatelessWidget), και όλη η μεταβλητή κατάσταση αποθηκεύεται σε ένα ξεχωριστό αντικείμενο State. Αυτό επιτρέπει στο Flutter να επαναχρησιμοποιεί τα widgets συγκρίνοντάς τα ανά τύπο και Key, και ταυτόχρονα να διατηρεί την τρέχουσα κατάσταση μεταξύ ανακατασκευών.

Σύμφωνα με τη Google (Flutter Architectural Overview, 2026), το StatefulWidget είναι βέλτιστο για σενάρια όπου η κατάσταση αλλάζει περισσότερες από μία φορά κατά τη διάρκεια ζωής του widget: πεδία κειμένου, κινητικά, χρονομετρητές, ροές δεδομένων, ασύγχρονες φορτώσεις. Για εφάπαξ αρχικοποίηση, το StatelessWidget είναι αρκετό.

Πότε είναι απαραίτητο το StatefulWidget

StatefulWidget είναι υποχρεωτικό όταν το widget πρέπει να αντιδρά σε εξωτερικά συμβάντα: πάτημα κουμπιού, ολοκλήρωση HTTP αιτήματος, ενημέρωση δεδομένων από βάση δεδομένων, συνδρομή σε WebSocket. Είναι επίσης απαραίτητο για widgets με κινητικά, πεδία κειμένου με controllers και στοιχεία που διαχειρίζονται το focus. Αν το widget μόνο εμφανίζει δεδομένα και δεν δημιουργεί συμβάντα — χρησιμοποιήστε StatelessWidget.

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

Το StatefulWidget αποτελείται από δύο κλάσεις: αυτό καθαυτό το StatefulWidget (ελαφρύ, αμετάβλητο) και το State (βαρύ, μεταβλητό). Το πλαίσιο δημιουργεί το State μέσω της μεθόδου createState(), που καλείται μία φορά κατά την ενσωμάτωση στο δέντρο. Το State λαμβάνει αναφορά στο widget μέσω της ιδιότητας widget και μπορεί να έχει πρόσβαση στα πεδία του σε οποιοδήποτε στιγμή του κύκλου ζωής.

Κύκλος ζωής του StatefulWidget

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

createState

createState — η πρώτη μέθοδος του κύκλου ζωής, που καλείται κατά την ενσωμάτωση του StatefulWidget στο δέντρο. Πρέπει να επιστρέφει μια νέα περίπτωση State που σχετίζεται με αυτό το widget. Αυτή η μέθοδος καλείται ακριβώς μία φορά κατά τη διάρκεια ζωής του στοιχείου. Είναι σημαντικό να μην εκτελούνται βαριές λειτουργίες εδώ — το createState πρέπει να είναι όσο το δυνατόν ελαφρύτερο.

initState

initState — καλείται αμέσως μετά τη δημιουργία του State, πριν από την πρώτη κατασκευή UI. Εδώ εκτελούνται: αρχικοποίηση ελεγκτών (TextEditingController, AnimationController), εγγραφή σε ροές δεδομένων (StreamSubscription), ρύθμιση χρονομετρητών και αρχική αρχικοποίηση πεδίων. Σύμφωνα με τα έγγραφα Flutter (Flutter.dev, 2026), στο initState δεν μπορείτε να καλέσετε το BuildContext.of() — το δέντρο δεν είναι ακόμη πλήρως τοποθετημένο.

didChangeDependencies

didChangeDependencies — καλείται μετά το initState και κάθε φορά που αλλάζουν οι εξαρτήσεις InheritedWidget. Αυτό είναι το κατάλληλο σημείο για να καλέσετε MediaQuery.of(context) ή να εγγραφείτε στο Theme — τιμές που μπορούν να αλλάξουν κατά τη λειτουργία της εφαρμογής. Αν το widget χρησιμοποιεί InheritedWidget, η λογική αρχικοποίησης πρέπει να είναι εδώ, όχι στο initState.

build και didUpdateWidget

build — η κύρια μέθοδος που επιστρέφει το δέντρο widgets. Καλείται μετά το initState, μετά το didChangeDependencies και μετά από κάθε setState. didUpdateWidget καλείται όταν ο γονέας ανακατασκευάζει και μεταβιβάζει το StatefulWidget με νέες παραμέτρους. Εδώ μπορείτε να συγκρίνετε τα παλιά και νέα πεδία του widget και, αν χρειαστεί, να ενημερώσετε την κατάσταση.

dispose

dispose — το τελικό στάδιο του κύκλου ζωής. Εδώ απελευθερώνονται όλοι οι πόροι: ακύρωση εγγραφών από ροές, διαγραφή ελεγκτών, ακύρωση χρονομετρητών. Η μη κλήση του dispose οδηγεί σε διαρροές μνήμης. Μετά το dispose, το State θεωρείται νεκρό — η κλήση του setState μέσα σε αυτό πετάει εξαίρεση.

Πώς λειτουργεί το StatefulWidget;

Ο μηχανισμός λειτουργίας του StatefulWidget βασίζεται στη συντονισμένη εργασία τριών οντοτήτων: Widget (ελαφρύς περιγραφή), Element (ενδιάμεσο στρώμα) και State (αποθήκη δεδομένων). Όταν το Flutter συναντά ένα StatefulWidget στην περιγραφή, δημιουργεί ένα StatefulElement που καλεί το createState και αποθηκεύει την αναφορά στο αντικείμενο State. Κατά την ανακατασκευή του γονέα, το Flutter συγκρίνει το νέο widget με το τρέχον Element — αν ο τύπος και το Key συμπίπτουν, το Element ενημερώνεται, ενώ το State παραμένει το ίδιο.

Η κατάσταση αλλάζει μόνο μέσω της κλήσης setState, που ειδοποιεί το πλαίσιο για την ανάγκη ανακατασκευής. Είναι σημαντικό να κατανοήσετε: το setState δεν αλλάζει αυτόματα την κατάσταση — απλώς σημαίνει το widget ως «βρώμικο». Ο προγραμματιστής ενημερώνει ο ίδιος τα πεδία του State στο callback που μεταβιβάζεται στο setState. Μετά τον τερματισμό του callback, το Flutter καλεί το build και ενημερώνει το UI.

Σύμφωνα με την ομάδα Dart/Flutter (Dart Language Specification, 2026), αυτός ο διαχωρισμός εγγυάται ότι όλες οι αλλαγές κατάστασης συμβαίνουν σύγχρονα πριν από την κλήση του build, αποκλείοντας την κατάσταση όπου το UI εμφανίζει μερικώς ενημερωμένα δεδομένα. Αυτός είναι ο βασικός μηχανισμός συνέπειας διεπαφής στο Flutter.

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

Ας δούμε ένα απλό StatefulWidget — έναν μετρητή κλικ κουμπιού. Δείχνει το βασικό μοτίβο: δημιουργία State, αρχικοποίηση πεδίου στο initState, αλλαγή μέσω setState:

dart
class CounterScreen extends StatefulWidget {
  const CounterScreen({super.key});

  @override
  State<CounterScreen> createState() => _CounterScreenState();
}

class _CounterScreenState extends State<CounterScreen> {
  int _count = 0;

  void _increment() {
    setState(() {
      _count++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('Αριθμός: $_count'),
        ElevatedButton(
          onPressed: _increment,
          child: const Text('Αύξηση'),
        ),
      ],
    );
  }
}

Παράδειγμα με ασύγχρονη φόρτωση δεδομένων και διαχείριση κύκλου ζωής. Το StatefulWidget φορτώνει δεδομένα από το δίκτυο και εμφανίζει την κατάσταση φόρτωσης:

dart
class UserProfilePage extends StatefulWidget {
  final String userId;
  const UserProfilePage({super.key, required this.userId});

  @override
  State<UserProfilePage> createState() => _UserProfilePageState();
}

class _UserProfilePageState extends State<UserProfilePage> {
  UserModel? _user;
  bool _isLoading = true;

  @override
  void initState() {
    super.initState();
    _loadUser();
  }

  Future<void> _loadUser() async {
    final user = await UserService.fetchUser(widget.userId);
    setState(() {
      _user = user;
      _isLoading = false;
    });
  }

  @override
  Widget build(BuildContext context) {
    if (_isLoading) return const CircularProgressIndicator();
    return Text('Γεια, ${_user!.name}');
  }
}

Στο δεύτερο παράδειγμα είναι σημαντικό να σημειωθεί: το initState ξεκινά μια ασύγχρονη λειτουργία, αλλά η ίδια η μέθοδος δεν είναι ασύγχρονη. Η ασυγχρονία υλοποιείται μέσω async/await μέσα στην ξεχωριστή μέθοδο _loadUser, η οποία ενημερώνει την κατάσταση μέσω setState μετά την ολοκλήρωση του αιτήματος. Αυτή η προσέγγιση εγγυάται ότι το widget θα εμφανίσει σωστά τον δείκτη φόρτωσης πριν λάβει τα δεδομένα.

StatefulWidget vs StatelessWidget

Η επιλογή μεταξύ StatefulWidget και StatelessWidget δεν είναι μόνο ζήτημα ύπαρξης κατάστασης. Το StatefulWidget παρέχει έναν πλήρη κύκλο ζωής με τις μεθόδους initState, didChangeDependencies, didUpdateWidget και dispose, που είναι απαραίτητο για την εργασία με ελεγκτές, κινητικά και ροές. Το StatelessWidget, από την άλλη πλευρά, δεν έχει αυτές τις μεθόδους και είναι πάντα ελαφρύτερο για το πλαίσιο.

Σύσταση της ομάδας Flutter (Flutter docs, 2026) — ελαχιστοποιήστε τον αριθμό των StatefulWidget στην εφαρμογή, ανυψώνοντας την κατάσταση προς τα πάνω στο δέντρο (State Hoisting) ή χρησιμοποιώντας λύσεις διαχείρισης κατάστασης (Riverpod, Bloc, Provider). Κάθε StatefulWidget δημιουργεί ένα αντικείμενο State που ζει μέχρι την αφαίρεση του στοιχείου — όσο περισσότερα τέτοια widgets, τόσο μεγαλύτερο το φορτίο μνήμης.

ΚριτήριοStatefulWidgetStatelessWidget
ΚατάστασηΜεταβλητήΑμετάβλητη
Κύκλος ζωής6 στάδιαΜόνο build
Αντικείμενο StateΔημιουργείται ξεχωριστάΔεν απαιτείται
setStateΔιαθέσιμοΜη διαθέσιμο
ΕγγραφέςinitState/disposeΔεν υποστηρίζονται
const κατασκευαστήςΠεριορισμένοςΠλήρως υποστηριζόμενος
Κατανάλωση μνήμηςΠερισσότερηΜικρότερη

Απόδοση και βελτιστοποίηση

StatefulWidget απαιτεί περισσότερους πόρους από το StatelessWidget λόγω της ανάγκης δημιουργίας και συντήρησης του αντικειμένου State. Ωστόσο, η σωστή χρήση του StatefulWidget δεν οδηγεί σε προβλήματα απόδοσης αν τηρούνται μερικοί κανόνες. Πρώτον, αποφεύγετε τη βαθιά έμπνευση του StatefulWidget — κάθε επίπεδο προσθέτει επιβάρυνση για τη διάσχιση του δέντρου. Δεύτερον, χωρίστε το σύνθετο StatefulWidget σε πολλά απλά widgets, κάθε ένα υπεύθυνο για το δικό του μέρος της κατάστασης.

Σύμφωνα με την έρευνα Flutter Performance (Flutter.dev, Φεβρουάριος 2026), η συχνότερη αιτία πτώσης FPS είναι η κλήση setState στο γονικό widget που ανακατασκευάζει όλους τους απογόνους, συμπεριλαμβανομένων και των StatelessWidget που δεν έχουν αλλάξει την εμφάνισή τους. Η λύση — μεταφέρετε το μεταβλητό μέρος του UI σε ένα ξεχωριστό StatefulWidget, έτσι ώστε το setState να ανακατασκευάζει μόνο το ελάχιστο απαιτούμενων widgets.

Η χρήση const μέσα στο State είναι μια ακόμη σημαντική τεχνική. Αν τα θυγατρικά widgets είναι δηλωμένα ως const, το Flutter δεν θα τα ανακατασκευάσει κατά την κλήση setState στον γονέα. Αυτό μειώνει το φορτίο του πλαισίου και μειώνει τον χρόνο απόδοσης κάθε καρέ.

Αποφύγετε συχνές setState

Κάθε κλήση setState εκκινά μια πλήρη ανακατασκευή του widget. Αν η κατάσταση αλλάζει με υψηλή συχνότητα (π.χ. κινητική ή ροή δεδομένων), σκεφτείτε τη χρήση AnimatedBuilder, ValueListenableBuilder ή StreamBuilder αντί για χειροκίνητη κλήση setState. Αυτά τα widgets βελτιστοποιούν την ανακατασκευή, ενημερώνοντας μόνο εκείνο το μέρος του UI που πραγματικά άλλαξε.

Συνηθισμένα λάθη

Το πρώτο συνηθισμένο λάθος με το StatefulWidget — η κλήση setState μετά από dispose. Όταν το widget αφαιρεθεί από το δέντρο, το State θεωρείται νεκρό και κάθε κλήση setState πετάει την εξαίρεση «setState called after dispose». Το πιο συχνά αυτό συμβαίνει όταν μια ασύγχρονη λειτουργία ολοκληρώνεται μετά την αφαίρεση του widget. Η λύση — ελέγξτε τη σημαία mounted πριν την κλήση setState ή ακυρώστε τις ασύγχρονες λειτουργίες στο dispose.

Το δεύτερο λάθος — η εκτέλεση βαρέων υπολογισμών στη μέθοδο build. Δεδομένου ότι το build καλείται σε κάθε setState και σε κάθε ανακατασκευή του γονέα, όλοι οι υπολογισμοί πρέπει να είναι όσο το δυνατόν ελαφρύτεροι. Αν πρέπει να εκτελέσετε μια λειτουργία έντασης πόρων — μεταφέρετε την σε ένα ξεχωριστό Isolate ή αποθηκεύστε το αποτέλεσμα σε ένα πεδίο State.

Το τρίτο λάθος — η έλλειψη κλήσης super.initState() και super.dispose(). Υπερβαίνοντας αυτές τις μεθόδους, ο προγραμματιστής είναι υποχρεωμένος να καλέσει τη γονική υλοποίηση. Αν αυτό δεν γίνει, το πλαίσιο δεν μπορεί να διαχειριστεί σωστά την κατάσταση του Element, πράγμα που οδηγεί σε δύσκολα εντοπίσιμα σφάλματα.

Συστάσεις για την αποφυγή λαθών

  • Πάντα ελέγχετε το mounted πριν το setState σε ασύγχρονα callbacks
  • Μην ξεχνάτε να καλείτε super.initState() και super.dispose()
  • Μην κάνετε HTTP αιτήματα απευθείας στο build — χρησιμοποιήστε το initState
  • Ακυρώστε όλες τις εγγραφές στο dispose
  • Χρησιμοποιείτε ελάχιστο αριθμό StatefulWidget στο έργο

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

Σε τι διαφέρει το StatefulWidget από το StatelessWidget;

StatefulWidget μπορεί να αλλάξει την κατάστασή του μέσω setState, έχει κύκλο ζωής (initState, dispose) και δημιουργεί ξεχωριστό αντικείμενο State. Το StatelessWidget δεν μπορεί να αλλάξει κατάσταση και δεν έχει μεθόδους κύκλου ζωής — απλώς εμφανίζει τα δεδομένα που του δίνονται.

Πόσες φορές καλείται το createState;

createState καλείται ακριβώς μία φορά για κάθε περίπτωση StatefulElement. Ακόμα και αν ο γονέας ανακατασκευάζεται πολλές φορές, όσο ο τύπος και το Key του widget δεν αλλάζουν, το createState δεν καλείται — χρησιμοποιείται το υπάρχον αντικείμενο State.

Τι θα συμβεί αν δεν κληθεί το dispose;

Οι πόροι δεν θα απελευθερωθούν: οι ελεγκτές θα συνεχίσουν να λειτουργούν στο παρασκήνιο, οι εγγραφές ροών θα παραμείνουν ενεργές, οι χρονομετρητές δεν θα ακυρωθούν. Αυτό οδηγεί σε διαρροές μνήμης και μπορεί να προκαλέσει κλήση setState μετά από dispose, που πετάει εξαίρεση.

Μπορεί το StatefulWidget να είναι const;

Ναι, ο κατασκευαστής του StatefulWidget μπορεί να είναι const. Ωστόσο, αυτό δεν προσφέρει το ίδιο όφελος όπως για το StatelessWidget — το αντικείμενο State θα δημιουργηθεί ούτως ή άλλως κατά την πρώτη ενσωμάτωση. Το const επηρεάζει μόνο το ίδιο το widget (ελαφρύ περιτύλιγμα), όχι το State.

Για τι χρησιμεύει η μέθοδος didUpdateWidget;

didUpdateWidget καλείται όταν ο γονέας μεταβιβάζει το StatefulWidget με νέες παραμέτρους. Αυτό είναι απαραίτητο για να συγχρονιστεί η κατάσταση με νέα δεδομένα — για παράδειγμα, αν το userId άλλαξε στις παραμέτρους, πρέπει να φορτωθεί το προφίλ του νέου χρήστη.

Σύνοψη

  • StatefulWidget — widget με μεταβλητή κατάσταση που χρησιμοποιεί ξεχωριστό αντικείμενο State για αποθήκευση δεδομένων και διαχείριση κύκλου ζωής
  • Κύκλος ζωής αποτελείται από createState, initState, didChangeDependencies, build, didUpdateWidget και dispose, το καθένα με τον δικό του σκοπό
  • setState — ο μόνος νόμιμος τρόπος ειδοποίησης του πλαισίου για αλλαγή κατάστασης, μετά τον οποίο το build καλείται αυτόματα
  • mounted — σημαία που πρέπει να ελέγχεται πριν από το setState σε ασύγχρονες λειτουργίες για αποφυγή εξαίρεσης μετά από dispose
  • Απόδοση — το StatefulWidget απαιτεί περισσότερους πόρους από το StatelessWidget; συνιστάται η ελαχιστοποίηση του αριθμού τους με μεταφορά κατάστασης σε εξωτερικά στρώματα
  • const θυγατρικά widgets μέσα στο State επιτρέπουν τη μείωση του όγκου ανακατασκευής κατά την κλήση setState, βελτιώνοντας την απόδοση
  • Σωστή επιλογή — χρησιμοποιείτε το StatefulWidget μόνο όταν το widget πρέπει να διαχειρίζεται μεταβλητά δεδομένα ή ασύγχρονες λειτουργίες

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

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

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

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