FutureBuilder — је виџет у Flutter-у који аутоматски обнавља свој интерфејс на основу тренутног стања AsyncSnapshot-а, добијеног из прослеђеног Future-а. За разлику од ручног позивања setState након await, FutureBuilder пружа декларативни приступ: претплаћује се на Future при првом рендеровању и позива builder функцију при свакој промени стања — учитавање, грешка или готови подаци. Према Flutter API Reference (2026), FutureBuilder је посебно користан за учитавање података из мреже, читање из базе података и све асинхроне операције где UI треба да прикаже индикатор учитавања, поруку о грешци или готов садржај.
Главне тачке
FutureBuilder — је уграђени Flutter виџет из пакета widgets, који прима Future<T> и builder функцију. Када се стање Future-а промени (извршава се, завршен са подацима, завршен са грешком) FutureBuilder аутоматски обнавља UI, позивајући builder са новим AsyncSnapshot-ом. Ово елиминише потребу за ручним управљањем стањем учитавања путем setState-а и заставица.
За разлику од StreamBuilder-а, који ради са токовима података (Stream), FutureBuilder је намењен за једнократне асинхроне операције: HTTP захтев, читање из датотеке, упит бази података. FutureBuilder сам управља претплатом на Future: при првом прављењу покреће Future и прати његов завршетак. При уништењу виџета, FutureBuilder не отказује Future — то је одговорност програмера.
Према Flutter Cookbook (2026), FutureBuilder се препоручује за случајеве када се асинхрона операција покреће једном при иницијализацији екрана. За понављајуће операције или токове података користите StreamBuilder. Оба виџета праде исти образац Reactive UI, али FutureBuilder је оптимизован за једнократне захтеве.
Унутрашња имплементација FutureBuilder-а се претплаћује на Future путем Future.then и catchError. При покретању, FutureBuilder поставља connectionState на ConnectionState.waiting и позива builder са празним подацима. При успешном завршетку, connectionState се мења у ConnectionState.done са подацима. При грешци, snapshot.error се попуњава објектом грешке. Свака промена покреће обнављање виџета.
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('Корисници')),
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('Грешка: ${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). Ако се родитељски виџет обнавља, FutureBuilder се такође обнавља. Да бисте спречили поновне позиве, уверите се да се Future креира ван build методе — иначе сваки позив build ствара нови Future.
Сачувајте Future у пољу StatefulWidget-а (у initState) или користите мемоизацију. Ако се Future креира унутар build методе, сваки позив build ће креирати нови Future, а FutureBuilder ће поново покренути асинхрону операцију. За StatelessWidget користите пакет cached_future или keep-alive виџете да би се 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. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође