StreamBuilder: co to je, princip fungování a aplikace ve Flutter

Autor: IT Sectr Publikováno: 2026-07-03 Doba čtení: 8 min

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 — widget přijímající Stream a snapshot dat pro reaktivní vykreslování UI
  • Snapshot obsahuje connectionState, data a error, určující aktuální stav proudu
  • ConnectionState prochází čtyřmi fázemi: none, waiting, active, done
  • AsyncSnapshot — neměnný objekt, který zaručuje konzistenci dat na každém snímku
  • StreamController spravuje proud: přidává data, zpracovává chyby a zavírá Stream

Co je StreamBuilder

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.

Jak funguje StreamBuilder

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.

ConnectionState: čtyři stavy proudu

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.

ConnectionState.none

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.

ConnectionState.waiting

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í.

ConnectionState.active

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.

ConnectionState.done

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í.

Použití StreamController ke správě proudu

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říklady kódu s StreamBuilder

Příklad 1 demonstruje časovač s odpočítáváním pomocí StreamController a StreamBuilder.

dart
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ů.

dart
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.

Typické chyby při práci s StreamBuilder

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

Čím se StreamBuilder liší od FutureBuilder?

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.

Co je AsyncSnapshot v StreamBuilder?

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.

Jak zpracovat chybu v StreamBuilder?

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.

Lze použít jeden Stream ve více StreamBuilder?

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.

Jak zabránit přestavbě StreamBuilder při každé události?

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í

  • StreamBuilder — widget pro reaktivní stavbu UI na základě asynchronního datového proudu s podporou nepřetržité aktualizace rozhraní
  • AsyncSnapshot obsahuje connectionState (none, waiting, active, done), data a error — všechny stavy proudu
  • StreamController spravuje životní cyklus proudu: přidávání dat, zpracování chyb a zavírání proudu
  • Broadcast Stream umožňuje více StreamBuilder přihlásit se k jednomu proudu, single-subscription — pouze jednomu
  • Zpracování chyb je povinné: bez kontroly hasError může aplikace uváznout ve stavu načítání
  • Únik paměti — nejčastější problém: vždy zavírejte StreamController v dispose
  • Doporučení: vždy nastavte initialData a zpracujte všechny čtyři connectionState pro plynulé UX

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í.

Prodiskutovat projekt

Přečtěte si také