FutureBuilder — είναι ένα widget στο Flutter που αυτόματα ανακατασκευάζει τη διεπαφή του βάσει της τρέχουσας κατάστασης του AsyncSnapshot που λαμβάνεται από το παραδοθέν Future. Σε αντίθεση με την μανυαλική κλήση setState μετά από await, το FutureBuilder παρέχει μια δηλωτική προσέγγιση: εγγράφεται στο Future κατά την πρώτη απόδοση και καλεί τη συνάρτηση builder σε κάθε αλλαγή κατάστασης — φόρτωση, σφάλμα ή έτοιμα δεδομένα. Σύμφωνα με το Flutter API Reference (2026), το FutureBuilder είναι ιδιαίτερα χρήσιμο για τη φόρτωση δεδομένων από δίκτυο, ανάγνωση από βάση δεδομένων και οποιεσδήποτε ασύγχρονες λειτουργίες όπου το UI πρέπει να εμφανίζει δείκτη φόρτωσης, μήνυμα σφάλματος ή έτοιμο περιεχόμενο.
Κύρια σημεία
FutureBuilder — είναι ένα ενσωματωμένο widget του Flutter από το πακέτο widgets, που δέχεται Future<T> και μια συνάρτηση builder. Όταν η κατάσταση του Future αλλάζει (εκτελείται, ολοκληρώθηκε με δεδομένα, ολοκληρώθηκε με σφάλμα) το FutureBuilder αυτόματα ανακατασκευάζει το UI, καλώντας το builder με νέο AsyncSnapshot. Αυτό εξαλείφει την ανάγκη μανυαλικής διαχείρισης της κατάστασης φόρτωσης μέσω setState και σημαιών.
Σε αντίθεση με το StreamBuilder, που εργάζεται με ροές δεδομένων (Stream), το FutureBuilder προορίζεται για εφάπαξ ασύγχρονες λειτουργίες: αίτημα HTTP, ανάγνωση από αρχείο, ερώτημα σε βάση δεδομένων. Το FutureBuilder διαχειρίζεται μόνο τη συνδρομή στο Future: κατά την πρώτη κατασκευή εκκινά το Future και παρακολουθεί την ολοκλήρωσή του. Κατά την καταστροφή του widget, το FutureBuilder δεν ακυρώνει το Future — αυτή είναι ευθύνη του αναπτυκτή.
Σύμφωνα με το Flutter Cookbook (2026), το FutureBuilder συνιστάται για περιπτώσεις όπου η ασύγχρονη λειτουργία εκτελείται μία φορά κατά την αρχικοποίηση της οθόνης. Για επαναλαμβανόμενες λειτουργίες ή ροές δεδομένων χρησιμοποιήστε το StreamBuilder. Και τα δύο widgets ακολουθούν το ίδιο πρότυπο Reactive UI, αλλά το FutureBuilder είναι βελτιστοποιημένο για εφάπαξ αιτήματα.
Η εσωτερική υλοποίηση του FutureBuilder εγγράφεται στο Future μέσω Future.then και catchError. Κατά την έναρξη, το FutureBuilder ορίζει το connectionState σε ConnectionState.waiting και καλεί το builder με κενά δεδομένα. Σε επιτυχημένη ολοκλήρωση, το connectionState αλλάζει σε ConnectionState.done με δεδομένα. Σε σφάλμα, το snapshot.error πληρώνεται με το αντικείμενο σφάλματος. Κάθε αλλαγή πυροδοτεί την ανακατασκευή του widget.
AsyncSnapshot — είναι ένα αντικείμενο-δοχείο που το FutureBuilder μεταβιβάζει στη συνάρτηση builder σε κάθε αλλαγή κατάστασης. Περιέχει όλες τις πληροφορίες σχετικά με την τρέχουσα κατάσταση της ασύγχρονης λειτουργίας: αν η φόρτωση βρίσκεται σε εξέλιξη, ποια δεδομένα ελήφθησαν, αν προέκυψε σφάλμα. Η κατανόηση του AsyncSnapshot είναι το κλειδί για τη σωστή κατασκευή UI με FutureBuilder.
| Ιδιότητα | Τύπος | Περιγραφή |
|---|---|---|
| connectionState | ConnectionState | Τρέχουσα κατάσταση σύνδεσης (none, waiting, active, done) |
| data | T? | Δεδομένα που λήφθηκαν από το Future (null μέχρι την ολοκλήρωση ή σε περίπτωση σφάλματος) |
| error | Object? | Αντικείμενο σφάλματος αν το Future ολοκληρώθηκε με εξαίρεση |
| hasData | bool | true αν το data δεν είναι null και η κατάσταση είναι ConnectionState.done |
| hasError | bool | true αν το Future ολοκληρώθηκε με σφάλμα |
Το enum ConnectionState καθορίζει τη φάση της ασύγχρονης λειτουργίας. None — αρχική κατάσταση όταν το Future δεν έχει ακόμα εκκινήσει (χρησιμοποιείται σπάνια, συνήθως στην πρώτη κατασκευή χωρίς initialData). Waiting — το Future εκτελείται, τα δεδομένα δεν έχουν ακόμα ληφθεί. Active — χρησιμοποιείται μόνο από το StreamBuilder για ροές με μερικά δεδομένα. Done — το Future ολοκληρώθηκε, τα δεδομένα είναι διαθέσιμα μέσω snapshot.data ή το σφάλμα μέσω snapshot.error.
Η σωστή διαχείριση όλων των καταστάσεων του AsyncSnapshot στη συνάρτηση builder είναι υποχρεωτική απαίτηση για κώδικα παραγωγής. Αν δεν χειριστείτε την κατάσταση waiting, ο χρήστης θα δεί μια κενή οθόνη κατά τη διάρκεια της φόρτωσης. Αν δεν χειριστείτε το hasError, ο χρήστης θα λάβει Exception χωρίς εξήγηση. Προτεινόμενο πρότυπο: έλεγχος hasError → έλεγχος hasData → προεπιλεγμένη εμφάνιση φόρτωσης.
Το FutureBuilder μπορεί να χρησιμοποιηθεί σε αρκετά τυπικά πρότυπα, καθένα από τα οποία επιλύει μια συγκεκριμένη εργασία. Ας εξετάσουμε τα κύρια σενάρια: φόρτωση δεδομένων κατά την αρχικοποίηση, φόρτωση με προφυλαξή, παράλληλα αιτήματα και διαχείριση σφαλμάτων με επανάληψη.
Το πιο συνηθισμένο πρότυπο — FutureBuilder στη μέθοδο build του StatefulWidget ή StatelessWidget. Το Future μεταβιβάζεται από το initState ή δημιουργείται απευθείας στο build. Είναι σημαντικό να μην δημιουργείτε το Future στη μέθοδο build κάθε φορά που γίνεται ανακατασκευή — αυτό οδηγεί σε επαναλημβανόμενα αιτήματα. Χρησιμοποιήστε το Future που αποθηκεύεται στο πεδίο του State.
Για την αποφυγή επαναλημβανόμενων αιτημάτων, το FutureBuilder μπορεί να συνδυαστεί με το CachedNetworkImage ή τοπική προφυλαξή. Μετά την πρώτη φόρτωση, τα δεδομένα αποθηκεύονται στη μνήμη ή στα SharedPreferences, και το FutureBuilder εμφανίζει άμεσα τα προφυλαγμένα δεδομένα, ενώ παράλληλα τα ενημερώνει από το δίκτυο. Αυτό βελτιώνει την εμπειρία χρήστη με άμεση απόκριση.
Σύμφωνα με το pub.dev (2026), η προφυλαξή είναι ιδιαίτερα σημαντική για εικόνες και λίστες δεδομένων. Το FutureBuilder με CachedNetworkImageProvider εμφανίζει αυτόματα την προφυλαγμένη εικόνα, και σε περίπτωση απουσίας της — δείκτη φόρτωσης με επακόλουθη εμφάνιση του ληφθέντος αρχείου.
FutureBuilder και η μανυαλική διαχείριση κατάστασης μέσω setState — δύο προσεγγίσεις στο ασύγχρονο UI στο Flutter. Κάθε μία έχει τα πλεονεκτήματα και τους περιορισμούς της. Η επιλογή εξαρτάται από την πολυπλοκότητα της οθόνης και τον αριθμό των ασύγχρονων λειτουργιών.
Το FutureBuilder κερδίζει σε απλότητα: δεν χρειάζεται να δημιουργήσετε πεδία για κατάσταση φόρτωσης, δεδομένα και σφάλμα — όλα διαχειρίζονται μέσω AsyncSnapshot. Είναι ιδανικό για απλές οθόνες με μία ασύγχρονη λειτουργία (ένα αίτημα HTTP, ανάγνωση βάσης δεδομένων). Ωστόσο, με 5+ ασύγχρονες λειτουργίες σε μία οθόνη, το FutureBuilder δημιουργεί υπερβολική έμπνευση — σχηματίζεται μια «πυραμίδα» από έμπνευς FutureBuilder.
Το setState με μανυαλικά flags κατάστασης παρέχει περισσότερο έλεγχο και αναγνωσιμότητα σε σύνθετη λογική. Για οθόνες με πολλά εξαρτώμενα αιτήματα (φόρτωση χρήστη → φόρτωση παραγγελιών του → φόρτωση λεπτομερειών παραγγελίας) είναι καλύτερο να χρησιμοποιείτε setState με ChangeNotifier ή Bloc. Σύμφωνα με τον Flutter State Management Guide (2026), για σύνθετα σενάρια συνιστάται η χρήση Riverpod ή Bloc αντί για FutureBuilder, καθώς παρέχουν καλύτερο διαχωρισμό της λογικής από την παρουσίαση.
Ας εξετάσουμε ένα πρακτικό παράδειγμα χρήσης του FutureBuilder για τη φόρτωση λίστας χρηστών από ένα REST API. Ο κώδικας επιδεικνύει τη σωστή διαχείριση και των τριών καταστάσεων AsyncSnapshot: φόρτωση, σφάλμα και έτοιμα δεδομένα.
class UserListPage extends StatefulWidget {
const UserListPage({super.key});
@override
State<UserListPage> createState() => _UserListPageState();
}
class _UserListPageState extends State<UserListPage> {
final Future<List<User>> usersFuture = UserRepository().fetchUsers();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Users')),
body: FutureBuilder<List<User>>(
future: usersFuture,
builder: (context, AsyncSnapshot<List<User>> snapshot) {
if (snapshot.hasError) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, size: 48, color: Colors.red),
const SizedBox(height: 16),
Text('Error: ${snapshot.error}'),
],
),
);
}
if (snapshot.hasData) {
final users = snapshot.data!;
return ListView.builder(
itemCount: users.length,
itemBuilder: (context, index) {
return ListTile(
leading: CircleAvatar(backgroundImage: NetworkImage(users[index].avatarUrl)),
title: Text(users[index].name),
subtitle: Text(users[index].email),
);
},
);
}
return const Center(child: CircularProgressIndicator());
},
),
);
}
}
Στο παράδειγμα, το FutureBuilder διαχειρίζεται και τις τρεις καταστάσεις. Σε περίπτωση σφάλματος, εμφανίζεται ένα εικονίδιο με μήνυμα σφάλματος. Σε επιτυχημένη φόρτωση — ListView με αβατάρ και ονόματα. Κατά τη διάρκεια της φόρτωσης — CircularProgressIndicator. Το Future είναι δηλωμένο ως πεδίο της κλάσης, πράγμα που αποτρέπει την επαναλημβανόμενη κλήση κατά την ανακατασκευή. Αυτό το πρότυπο καλύπτει το 90% των σεναρίων χρήσης του FutureBuilder σε εφαρμογές κινητών.
Συχνές Ερωτήσεις
Το FutureBuilder καλεί το builder σε κάθε αλλαγή κατάστασης του Future: πρώτη φορά κατά τη δημιουργία (connectionState: none ή waiting), δεύτερη φορά κατά την ολοκλήρωση (connectionState: done). Αν το γονικό widget ανακατασκευάζεται, το FutureBuilder επίσης ανακατασκευάζεται. Για να αποτραπείτε τις επαναλημβανόμενες κλήσεις, βεβαιωθείτε ότι το Future δημιουργείται εκτός της μεθόδου build — διαφορετικά, κάθε κλήση build δημιουργεί ένα νέο Future.
Αποθηκεύστε το Future στο πεδίο του StatefulWidget (στο initState) ή χρησιμοποιήστε memoization. Αν το Future δημιουργείται εντός της μεθόδου build, κάθε κλήση build θα δημιουργεί ένα νέο Future, και το FutureBuilder θα επανεκκινήσει την ασύγχρονη λειτουργία. Για StatelessWidget, χρησιμοποιήστε το πακέτο cached_future ή keep-alive widgets ώστε το Future να εκτελείται μία φορά ανεξάρτητα από τις ανακατασκευές.
Το FutureBuilder προορίζεται για εφάπαξ ασύγχρονες λειτουργίες (ένα αίτημα HTTP, μία ανάγνωση βάσης δεδομένων). Το StreamBuilder εργάζεται με ροές δεδομένων που μπορούν να εκπέμπουν πολλαπλές τιμές στη πάροδο του χρόνου (συνομιλία, ενημερώσεις τιμών, γεωλοκατία). Το StreamBuilder υποστηρίζει το ConnectionState.active για μερικά δεδομένα, ενώ το FutureBuilder υποστηρίζει μόνο waiting και done.
Για πολλά παράλληλα Future, χρησιμοποιήστε το Future.wait και μεταβιβάστε το αποτέλεσμα σε ένα μόνο FutureBuilder. Το Future.wait δέχεται μια λίστα Future και επιστρέφει Future<List> — όταν όλα τα Future ολοκληρωθούν, ο builder λαμβάνει έναν πίνακα αποτελεσμάτων. Για σειριακά αιτήματα, χρησιμοποιήστε μια αλυσίδα Future.then μέσα σε ένα μόνο Future ή έμπνευς FutureBuilder (λιγότερο αναγνώσιμο). Εναλλακτικά — το πακέτο riverpod με AsyncValue για πολλαπλές ασύγχρονες καταστάσεις.
Το FutureBuilder δεν ακυρώνει αυτόματα το Future. Για ακύρωση, χρησιμοποιήστε το CancelableOperation από το πακέτο async ή έναν ιδιοποιημένο μηχανισμό μέσω της σημαίας cancelled στο State. Στο dispose() ορίστε τη σημαία, και μετά την ολοκλήρωση του Future ελέγξτε την πριν καλέσετε το setState. Εναλλακτικά, χρησιμοποιήστε το πακέτο riverpod με AutoDispose, που ακυρώνει αυτόματα τις ασύγχρονες λειτουργίες κατά την έξοδο από την οθόνη.
Σύνοψη
Θα αναπτύξουμε μια εφαρμογή για κινητά έτοιμη για χρήση
Η IT Sectr δημιουργεί εφαρμογές iOS και Android για νεοφυείς επιχειρήσεις και επιχειρήσεις από το 2017. Θα σας συμβουλεύσουμε και θα προτείνουμε την καλύτερη λύση.
Διαβάστε επίσης