StreamBuilder — widget Flutter, který automaticky přestavuje rozhraní při přijetí nových dat z asynchronního proudu. Na rozdíl od FutureBuilder, který pracuje s jednorázovým výsledkem, StreamBuilder podporuje nepřetržitou aktualizaci UI po celý životní cyklus Stream. Podle oficiální dokumentace Flutter (2026) se StreamBuilder používá v aplikacích reálného času: chaty, zpravodajské kanály, monitorování senzorů a finanční tickery. Je to klíčový nástroj reaktivního programování, kde UI odráží stav dat bez ručních volání setState.
Hlavní body
StreamBuilder — je widget z balíčku Flutter SDK, který se přihlásí k odběru Stream a při každé nové události proudu přestaví svůj podřízený prvek. StreamBuilder přijímá objekt Stream a vrací widget na základě posledního snapshot získaného z proudu.
V architektuře Flutter patří StreamBuilder do skupiny Builder-widgetů, které oddělují stavbu UI od stavu dat. Na rozdíl od StatefulWidget, kde změna stavu vyžaduje explicitní volání setState, StreamBuilder reaguje na asynchronní události automaticky, což zjednodušuje kód a snižuje riziko chyb synchronizace.
Na rozdíl od FutureBuilder, který zpracovává jednu asynchronní hodnotu, je StreamBuilder určen pro nepřetržité datové proudy. FutureBuilder končí po přijetí prvního výsledku, zatímco StreamBuilder nadále naslouchá proudu a aktualizuje UI při každé nové události.
StreamBuilder se používá ve všech scénářích, kde data přicházejí nepřetržitě: WebSocket připojení, zpětná volání senzorů, oznámení Firebase, fronty událostí Bluetooth a vysílání stavu aplikace přes BLoC. Podle analýzy Flutter projektů na GitHub (2025) je StreamBuilder mezi třemi nejpoužívanějšími Builder-widgety spolu s FutureBuilder a LayoutBuilder.
Závěr: použijte StreamBuilder všude tam, kde UI musí odrážet neustále se měnící data, a vyhněte se ruční správě stavu pomocí StatefulWidget.
StreamBuilder se přihlásí k odběru Stream v okamžiku sestavení a odhlásí se při zničení widgetu. Pokaždé, když Stream vyšle událost, StreamBuilder obdrží nový AsyncSnapshot a zavolá funkci builder pro přestavbu UI.
Proces se skládá ze tří fází. První: StreamBuilder vytvoří odběr předaného Stream pomocí metody stream.listen. Druhá: při každé události StreamBuilder aktualizuje interní AsyncSnapshot a označí widget jako „špinavý“ pro přestavbu. Třetí: framework zavolá funkci builder s novým snapshot a UI zobrazí aktuální data.
Důležité: StreamBuilder interně používá StreamSubscription. Pokud je Stream předán přímo, StreamBuilder se přihlásí jednou při inicializaci. Pokud se Stream změní (např. při přestavbě rodiče), StreamBuilder se odhlásí ze starého proudu a přihlásí k novému. Toto chování je řízeno parametry initialData a buildWhen, které umožňují optimalizovat počet přestaveb.
Závěr: pochopení životního cyklu odběru je základem správného použití StreamBuilder. Nesprávná správa proudů vede k únikům paměti nebo zastaralým datům v UI.
Vlastnost connectionState objektu AsyncSnapshot určuje, v jaké fázi práce s proudem se StreamBuilder nachází. Rozlišují se čtyři stavy: none, waiting, active, done.
None — počáteční stav, kdy Stream ještě nezačal přenášet data. V tomto stavu je snapshot.connectionState roven ConnectionState.none a snapshot.data je null. Obvykle se v tomto stavu zobrazuje zástupný symbol nebo čekání na první událost. Pokud Stream neposkytuje počáteční data, StreamBuilder začíná z tohoto stavu.
Waiting — stav čekání na data z asynchronního proudu. Stream je aktivní, ale data ještě nedorazila. Tento stav nastává například při načítání dat ze sítě nebo otevírání dlouhotrvajícího spojení. V tomto stavu se obvykle zobrazuje CircularProgressIndicator nebo kostra načítání.
Active — proud vysílá data a UI zobrazuje aktuální informace. V tomto stavu je snapshot.hasData true a snapshot.data obsahuje poslední hodnotu z proudu. Pokud je Stream Broadcast Stream, aktivní stav může koexistovat s čekáním na nová data.
Done — proud je dokončen, nová data nebudou. Snapshot.data obsahuje poslední hodnotu předanou před uzavřením proudu. Pokud byl proud úspěšně dokončen, snapshot.hasError je false. Tento stav se používá pro zobrazení konečného výsledku: zpráva „Načítání dokončeno“ nebo přechod na další obrazovku.
Závěr: při vytváření UI pomocí StreamBuilder je nutné zpracovat všechny čtyři stavy, aby rozhraní správně zobrazovalo načítání, data, chyby a dokončení.
StreamController — je třída z balíčku dart:async, která vytváří a spravuje Stream. StreamController umožňuje přidávat data, zpracovávat chyby a zavírat proud, čímž řídí jeho životní cyklus.
StreamController existuje ve dvou typech: single-subscription (jeden odběratel) a broadcast (více odběratelů). Single-subscription controller přijímá pouze jednoho posluchače najednou — opětovné přihlášení způsobí výjimku. Broadcast controller umožňuje několika StreamBuilder současně naslouchat jednomu proudu, což je užitečné pro BLoC a sdílený stav aplikace.
Při vytváření StreamController pomocí StreamController<T>.broadcast() se data přidaná před prvním odběrem novému odběrateli nepřehrávají. Pokud potřebujete získat poslední hodnotu při připojení, použijte BehaviourSubject z balíčku rxdart, který ukládá do mezipaměti poslední událost.
Po dokončení práce s controllerem je nutné zavolat controller.close(). Nezavolání close vede k úniku prostředků: proud zůstává otevřený, odběratelé zůstávají v paměti a GC neuvolňuje související objekty.
Závěr: používejte StreamController s explicitní správou životního cyklu. Pro single-subscription proudy — standardní controller, pro sdílený stav — broadcast controller nebo BehaviourSubject.
Příklad 1 demonstruje časovač s odpočítáváním pomocí StreamController a StreamBuilder.
import 'dart:async';
class TimerWidget extends StatefulWidget {
const TimerWidget({super.key});
final StreamController<int> controller = StreamController<int>();
void startTimer() {
int count = 0;
Timer.periodic(Duration(seconds: 1), (timer) {
controller.sink.add(count++);
if (count > 10) {
controller.close();
timer.cancel();
}
});
}
}
V příkladu je vytvořen controller pro generování čísel od 0 do 10 v intervalu 1 sekundy. Po dosažení 10 se zavolá close a proud skončí. StreamBuilder přihlášený k stream tohoto controlleru bude zobrazovat každou novou hodnotu.
Příklad 2 — použití StreamBuilder s Broadcast Stream pro zobrazení dat z více zdrojů.
final StreamController<String> broadcastController =
StreamController<String>.broadcast();
StreamBuilder<String>(
stream: broadcastController.stream,
initialData: 'Waiting for data...',
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(
child: CircularProgressIndicator(),
);
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
}
return Text('Data: ${snapshot.data}');
},
)
Druhý příklad ukazuje zpracování všech stavů: initialData pro počáteční zobrazení, waiting pro indikátor načítání, hasError pro chyby a data pro úspěšný výsledek. Tento vzor je standardem pro produkční kód s StreamBuilder.
Závěr: používejte initialData k zabránění prázdné obrazovky v prvním okamžiku a vždy zpracovávejte hasError pro správné zobrazení chyb uživateli.
Chyba 1: vytváření nového Stream při každé přestavbě rodiče. Pokud je Stream předán výrazem, který při každém sestavení vytváří nový objekt, StreamBuilder se odhlásí ze starého proudu a přihlásí k novému, což způsobí nekonečný cyklus přestaveb. Řešení: použijte remembered proměnnou nebo StatefulWidget s pevným Stream.
Chyba 2: chybějící zpracování chyb. Stream může vysílat chyby prostřednictvím controller.sink.addError, a pokud builder nekontroluje snapshot.hasError, uživatel vidí prázdnou obrazovku nebo nekonečné načítání. Řešení: vždy kontrolujte hasError a zobrazte srozumitelnou zprávu.
Chyba 3: únik paměti kvůli neuzavřenému StreamController. Pokud controller není uzavřen v dispose, proud nadále existuje a GC neuvolňuje paměť. Řešení: volejte controller.close() v dispose a naslouchejte události done pro závěrečné akce.
Chyba 4: použití StreamBuilder s pomalou funkcí builder. Protože je builder volán při každé události proudu, těžké výpočty uvnitř něj vedou k vynechávání snímků. Řešení: přesuňte výpočty do samostatného izolátu nebo použijte Stream.map pro transformaci dat.
Závěr: StreamBuilder je mocný, ale náročný nástroj. Sledujte životní cyklus Stream, zpracovávejte chyby a vyhýbejte se těžkým operacím v builder.
Často kladené dotazy
FutureBuilder je určen pro jednorázový asynchronní výsledek: přihlásí se k Future, obdrží jednu hodnotu a dokončí práci. StreamBuilder se přihlásí k Stream, který může v čase vysílat více hodnot, a přestavuje UI při každé nové události.
AsyncSnapshot — neměnný objekt, který obsahuje aktuální stav odběru (connectionState), poslední přijatou hodnotu (data) a objekt chyby (error), pokud proud vyvolal výjimku.
Chyba se zpracovává pomocí vlastností snapshot.hasError a snapshot.error ve funkci builder. Pokud proud vyšle chybu metodou sink.addError, AsyncSnapshot obdrží error a builder musí zobrazit odpovídající zprávu nebo záložní UI.
Ano, pokud je Stream typu broadcast (vytvořený pomocí StreamController.broadcast). Single-subscription Stream povoluje pouze jednoho odběratele. Pro sdílení jednoho proudu mezi více widgety použijte broadcast controller nebo balíček rxdart s BehaviourSubject.
Použijte parametr buildWhen pro filtrování událostí, při kterých je třeba přestavět UI. Také aplikujte Stream.transformer nebo Stream.where pro filtrování dat před předáním StreamBuilder.
Shrnutí
Vyvineme mobilní aplikaci na klíč
IT Sectr vytváří aplikace pro iOS a Android pro startupy a podniky od roku 2017. Poradíme vám a navrhneme nejlepší řešení.
Přečtěte si také