State ist das zentrale Datenverwaltungsobjekt in Flutter, das mit StatefulWidget verbunden ist und für die Speicherung veränderlicher Informationen und den Aufbau der Benutzeroberfläche verantwortlich ist. Laut der offiziellen Flutter-Dokumentation (Flutter.dev, 2026) existiert State während des gesamten Widget-Lebenszyklus und überlebt dessen Neuerstellungen, wodurch Datenkonsistenz zwischen UI-Updates gewährleistet wird. Im Gegensatz zum Widget selbst kann State seine Felder ändern und über den setState-Aufruf eine Neuerstellung auslösen.
Wichtige Punkte
State ist ein Objekt in der Flutter-Architektur, das veränderliche Daten eines StatefulWidget speichert und bestimmt, wie diese Daten in der Benutzeroberfläche angezeigt werden. Jedes StatefulWidget erstellt beim Einfügen in den Baum genau ein State-Objekt über die Methode createState. State existiert unabhängig vom Widget: Wenn das Elternteil das StatefulWidget mit neuen Parametern neu erstellt, bleibt State gleich und erhält das aktualisierte Widget über die Eigenschaft widget.
Laut der Flutter Architectural Overview (Google, 2026) ist die Trennung von Widget und State eine bewusste architektonische Entscheidung, die es dem Framework ermöglicht, Baumelemente wiederzuverwenden. Das Widget (eine leichte Beschreibung) kann mehrmals erstellt und zerstört werden, aber State (ein schweres Objekt mit Daten) bleibt im Speicher, solange das Element im Baum ist. Dies verhindert Datenverlust bei häufigen Neuerstellungen von Eltern-Widgets.
State implementiert die Schnittstelle StatefulWidget über Generika: class _MyState extends State<MyWidget>. Das Generikum bindet State an einen bestimmten StatefulWidget-Typ und bietet typsicheren Zugriff auf seine Felder über die Eigenschaft widget.
Das State-Objekt wird in StatefulElement gespeichert — einer Zwischenschicht zwischen Widget und RenderObject. StatefulElement erstellt State über createState, behält einen Verweis darauf und übergibt State als Besitzer. Das Element wird nur zerstört, wenn das Widget aus dem Baum entfernt wird — bis dahin lebt State im Speicher.
Der State-Lebenszyklus ist deterministisch und besteht aus einer strengen Abfolge von Aufrufen. Das Verständnis dieser Abfolge ist die Grundlage für korrektes Ressourcenmanagement und die Vermeidung von Speicherlecks.
initState wird zuerst beim Erstellen von State aufgerufen. In dieser Methode werden Controller, Stream-Abonnements, Timer und Anfangswerte von Feldern initialisiert. Der Aufruf von super.initState() in der ersten Zeile ist obligatorisch. In der initState-Phase ist der Widget-Baum noch nicht vollständig montiert, daher können Methoden wie MediaQuery.of(context) möglicherweise nicht korrekt funktionieren.
didChangeDependencies wird nach initState und bei jeder Änderung von InheritedWidget-Abhängigkeiten aufgerufen. Hier, nicht in initState, sollte MediaQuery.of(context) oder Theme.of(context) aufgerufen werden, da der Baum zu diesem Zeitpunkt bereits montiert ist. Diese Methode wird auch aufgerufen, wenn das Widget in einen anderen Kontext verschoben wird, in dem InheritedWidget andere Werte bereitstellt.
build ist die Hauptmethode von State, die einen Widget-Baum zurückgibt. Sie wird nach initState, nach didChangeDependencies und nach jedem setState aufgerufen. Die build-Methode sollte keine Nebenwirkungen haben — sie beschreibt nur die Benutzeroberfläche basierend auf den aktuellen Werten der State-Felder.
didUpdateWidget wird aufgerufen, wenn das Elternteil das StatefulWidget mit neuen Parametern neu erstellt. State erhält Zugriff auf das alte Widget über oldWidget und kann es mit dem neuen vergleichen. Wenn sich Parameter geändert haben, kann der Zustand aktualisiert, neue Daten geladen oder eine Animation neu gestartet werden.
dispose ist die letzte Methode, in der alle Ressourcen freigegeben werden: Controller, Abonnements, Timer. Nach dispose wird State als tot markiert: mounted gibt false zurück, der Aufruf von setState löst eine Ausnahme aus. Der Aufruf von super.dispose() in der letzten Zeile der Methode ist obligatorisch.
| Methode | Wann aufgerufen | Obligatorisches super |
|---|---|---|
| initState | Beim Erstellen von State | Ja, in der ersten Zeile |
| didChangeDependencies | Nach initState und bei Änderung von InheritedWidget | Ja |
| build | Nach initState, didChangeDependencies, setState | Nein |
| didUpdateWidget | Bei einem neuen Widget vom Elternteil | Ja |
| setState | Bei Aufruf durch den Entwickler | Nein |
| dispose | Bei Entfernung aus dem Baum | Ja, in der letzten Zeile |
Der Arbeitsmechanismus von State basiert auf drei Schlüsselprinzipien: Assoziation mit Element, Reaktivität durch setState und Elternzugriff über die widget-Eigenschaft. Wenn Flutter den Elementbaum erstellt und auf ein StatefulElement stößt, ruft es createState des zugehörigen Widgets auf. Der erstellte State wird im Element gespeichert und existiert, bis das Element entfernt wird.
Beim Aufruf von setState markiert sich State als schmutzig und plant eine Neuerstellung für den nächsten Frame. Wichtig: setState ruft build nicht sofort auf — es registriert nur die Notwendigkeit einer Neuerstellung. Flutter sammelt alle schmutzigen Elemente im aktuellen Frame und erstellt sie stapelweise neu, was die Leistung optimiert. Nach dem build-Aufruf kehrt State in den sauberen Zustand zurück.
Die widget-Eigenschaft ermöglicht es State, die an den StatefulWidget-Konstruktor übergebenen Parameter zu lesen. Da StatefulWidget unveränderlich ist (wie StatelessWidget), ändern sich seine Felder nicht — wenn sich Parameter ändern, erstellt das Elternteil ein neues Widget, und State empfängt es über didUpdateWidget. Dies stellt sicher, dass State immer mit aktuellen Elterndaten arbeitet.
Ein einfaches State-Beispiel mit einem Feld, das von einem Timer geändert wird. Zeigt initState, setState und dispose:
class _TimerWidgetState extends State<TimerWidget> {
int _seconds = 0;
Timer? _timer;
@override
void initState() {
super.initState();
_timer = Timer.periodic(
const Duration(seconds: 1),
(_) => setState(() => _seconds++),
);
}
@override
void dispose() {
_timer?.cancel();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Text('$_seconds seconds elapsed');
}
}
Ein Beispiel mit der widget-Eigenschaft zum Zugriff auf Elternparameter und Reaktion auf deren Änderungen über didUpdateWidget:
class _GreetingState extends State<GreetingWidget> {
String _displayName = '';
@override
void initState() {
super.initState();
_displayName = _formatName(widget.name);
}
@override
void didUpdateWidget(GreetingWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.name != oldWidget.name) {
setState(() {
_displayName = _formatName(widget.name);
});
}
}
String _formatName(String name) => name.trim().isEmpty ? 'Guest' : name;
@override
Widget build(BuildContext context) {
return Text('Hello, $_displayName!');
}
}
Im zweiten Beispiel verfolgt State Änderungen des Eingabeparameters name und formatiert die Anzeige nur bei einer tatsächlichen Änderung neu. Ohne die Überprüfung widget.name != oldWidget.name würde die Methode bei jeder Neuerstellung des Elternteils aufgerufen, selbst wenn sich der Name nicht geändert hat — unnötige Arbeit für das Framework.
State und StatefulWidget sind zwei verschiedene Klassen in der Flutter-Architektur mit unterschiedlichen Rollen. StatefulWidget ist ein leichter unveränderlicher Wrapper, der die Widget-Konfiguration beschreibt und State erstellt. State ist ein schweres Objekt, das veränderliche Daten speichert, Abonnements verwaltet und die UI erstellt. Diese Trennung ermöglicht es Flutter, Widgets zu zerstören und zu erstellen, ohne den Zustand zu verlieren.
Alle Felder von StatefulWidget müssen final sein und im Konstruktor gesetzt werden — sie ändern sich nach der Erstellung nicht. State hingegen kann seine Felder jederzeit ändern, aber allen Änderungen muss ein setState-Aufruf vorausgehen, damit Flutter von der Notwendigkeit einer Neuerstellung erfährt. Dies ist der Hauptunterschied: StatefulWidget ist „was zu zeigen“, State ist „wie zu zeigen und welche Daten zu verwenden“.
Laut Flutter-Quellcode-Analyse (Flutter SDK, 2026) enthält StatefulWidget nur ein obligatorisches Feld — createState, während State Zugriff auf BuildContext hat, Streams abonnieren, Animationen und Controller verwalten kann. Es wird empfohlen, StatefulWidget so einfach wie möglich zu halten und die gesamte Logik in State zu verschieben.
Die Trennung von Widget und State ist eine architektonische Entscheidung, die die Unveränderlichkeit der Konfiguration gewährleistet. Wenn StatefulWidget selbst den Zustand speichern würde, ginge der Zustand bei jeder Neuerstellung des Elternteils verloren. Durch das Verschieben des Zustands in ein separates Objekt garantiert Flutter, dass Daten Neuerstellungen überleben, während Widgets leicht und vergleichbar bleiben.
Das State-Objekt ist isoliert — es hat keinen direkten Zugriff auf den State anderer Widgets. Für den Datenaustausch zwischen Widgets werden InheritedWidget oder externe Zustandsverwaltungstools verwendet: Provider, Riverpod, Bloc, Redux. Jeder Ansatz löst das Problem anders: InheritedWidget arbeitet über den Widget-Baum, Provider über einen DI-Container, Bloc über Ereignisströme.
Die Wahl des Tools hängt vom Projektumfang ab. Für eine kleine Anwendung reichen InheritedWidget und lokaler State aus. Für mittlere und große Projekte werden Riverpod oder Bloc empfohlen — sie gewährleisten Testbarkeit, Vorhersagbarkeit und Trennung der Logik von der UI. State wird dann nur für lokale Widget-Daten (Fokus, Scrollen, Animation) verwendet.
Laut der Flutter Community Survey 2025 (Flutter Foundation, Dezember 2025) ist Riverpod die beliebteste Zustandsverwaltungslösung in neuen Projekten (38%), gefolgt von Bloc (31%) und Provider (22%). Alle drei Tools sind mit State kompatibel und erfordern keine Aufgabe des Standardlebenszyklus.
Der erste Fehler ist, vor setState in einem asynchronen Callback die Überprüfung von mounted zu vergessen. Wenn ein Widget aus dem Baum entfernt wird (z. B. der Benutzer hat den Bildschirm verlassen), aber ein asynchroner Vorgang (HTTP-Anfrage) noch läuft, ist State nach dessen Abschluss bereits tot. Der Aufruf von setState in einem toten State löst eine Ausnahme aus. Die Überprüfung if (mounted) setState(...) löst das Problem.
Der zweite Fehler ist die Initialisierung von InheritedWidget-Abhängigkeiten in initState statt in didChangeDependencies. In initState ist der Kontext noch nicht montiert, daher wird MediaQuery.of(context) eine Ausnahme auslösen. Alle InheritedWidget-Abhängigkeiten sollten in didChangeDependencies oder in build eingerichtet werden.
Der dritte Fehler ist das Ändern von Feldern ohne Aufruf von setState. Wenn ein Entwickler ein State-Feld ohne setState ändert, erfährt Flutter nichts von der Änderung und die UI wird nicht aktualisiert. Zum Beispiel: _list.add(item) ohne nachfolgendes setState((){}) ändert die Liste, aber der Bildschirm bleibt gleich.
Ein Sicherheitsmuster für asynchrone Operationen in State:
Future<void> _fetchData() async {
final data = await ApiService.fetch();
if (mounted) {
setState(() => _data = data);
}
}
Die Überprüfung von mounted stellt sicher, dass setState nur auf einem lebenden State aufgerufen wird, und verhindert die Ausnahme „setState called after dispose“.
Häufig gestellte Fragen
StatefulWidget ist eine unveränderliche Widget-Konfiguration, während State ein veränderliches Objekt ist, das Daten speichert und den Lebenszyklus verwaltet. Das Widget kann neu erstellt werden, State nicht. StatefulWidget erstellt State über createState.
Genau eines. Die Methode createState wird einmal aufgerufen, wenn das StatefulWidget zum ersten Mal in den Baum eingefügt wird. Selbst wenn das Elternteil mehrmals neu erstellt wird, bleibt das State-Objekt dasselbe, bis sich der Typ oder der Key des Widgets ändert.
mounted ist ein boolesches Flag, das anzeigt, ob State sich im Widget-Baum befindet. Nach dem Aufruf von dispose wird mounted false. Es wird zur Überprüfung vor setState in asynchronen Callbacks verwendet, um Ausnahmen zu vermeiden.
Nein. State ist immer über Generika an ein bestimmtes StatefulWidget gebunden: State<T extends StatefulWidget>. State direkt ohne Verbindung zu einem Widget zu erstellen, ist architektonisch unmöglich.
Eine Ausnahme wird ausgelöst: „setState called after dispose“. Nach dispose gilt State als tot, und alle Versuche, die UI über setState neu zu erstellen, sind verboten. Die Lösung ist, vor jedem setState mounted zu überprüfen.
Zusammenfassung
Wir entwickeln eine mobile Applikation schlüsselfertig
IT Sectr entwickelt seit 2017 iOS- und Android-Apps für Startups und Unternehmen. Wir beraten Sie und schlagen die beste Lösung vor.
Lesen Sie auch