FutureBuilder — е widget във Flutter, който автоматично преизгражда интерфейса си въз основа на текущото състояние на AsyncSnapshot, получено от предадения Future. За разлика от ръчното извикване на setState след await, FutureBuilder предоставя декларативен подход: абонира се за Future при първото рендиране и извиква builder функцията при всяка промяна на състоянието — зареждане, грешка или готови данни. Според Flutter API Reference (2026), FutureBuilder е особено полезен за зареждане на данни от мрежа, четене от база данни и всякакви асинхронни операции, където UI трябва да показва индикатор за зареждане, съобщение за грешка или готово съдържание.
Основни точки
FutureBuilder — е вграден Flutter widget от пакета 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. И двата widget следват един и същ модел 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 показва кешираните данни незабавно, паралелно ги обновявайки от мрежата. Това подобрява UX чрез незабавен отговор.
Според pub.dev (2026), кеширането е особено важно за изображения и списъци с данни. FutureBuilder с CachedNetworkImageProvider автоматично показва кешираното изображение, а при липсата му — индикатор за зареждане с последващо показване на изтегления файл.
FutureBuilder и ръчно управление на състоянието чрез setState — два подхода към асинхронния UI във Flutter. Всеки има своите предимства и ограничения. Изборът зависи от сложността на екрана и броя на асинхронните операции.
FutureBuilder печели с простотата си: не е необходимо да декларирате полета за състояние на зареждане, данни и грешка — всичко се управлява чрез AsyncSnapshot. Идеален е за прости екрани с една асинхронна операция (една HTTP заявка, четене от база данни). Въпреки това, при 5+ асинхронни операции на един екран, FutureBuilder създава прекомерно влагане — образува се „пирамида" от вложени FutureBuilder-и.
setState с ръчни флагове на състоянието дава повече контрол и четимост при сложна логика. За екрани с множество зависими заявки (зареди потребител → зареди неговите поръчки → зареди детайли на поръчка) е по-добре да използвате 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) или използвайте мемоизация. Ако Future се създава вътре в build метода, всяко извикване на build ще създаде нов Future и FutureBuilder ще рестартира асинхронната операция. За StatelessWidget използвайте пакета cached_future или keep-alive widget-ове, така че 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 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също