StatefulWidget ist ein Flutter-Widget mit veränderlichem Zustand, das es der UI ermöglicht, auf Benutzeraktionen, asynchrone Ereignisse und Datenströme zu reagieren. Laut der offiziellen Flutter-Dokumentation (Flutter.dev, 2026) wird StatefulWidget für alle interaktiven Elemente einer Anwendung verwendet: Eingabeformulare, Animationen, Kontrollkästchen, Schalter und Bildschirme, die Daten aus dem Netzwerk laden. Im Gegensatz zu StatelessWidget erstellt es ein separates State-Objekt, das während des gesamten Lebenszyklus bestehen bleibt und neu aufgebaut werden kann, ohne das Widget selbst neu zu erstellen.
Wichtige Punkte
StatefulWidget ist eine Flutter-Klasse, die ihren Zustand als Reaktion auf Benutzeraktionen, Systemereignisse oder asynchrone Operationen ändern kann. Im Gegensatz zu StatelessWidget wird StatefulWidget nicht direkt gerendert — es erstellt ein State-Objekt, das für das Rendern zuständig ist. Diese Aufteilung in zwei Klassen (Widget und State) ermöglicht es Flutter, die UI neu aufzubauen, ohne das Widget selbst neu zu erstellen, was bei häufigen Aktualisierungen einen erheblichen Leistungsvorteil bietet.
Die Architektur von StatefulWidget folgt dem Muster der „Trennung von Veränderlichem und Unveränderlichem“: Das Widget selbst bleibt unveränderlich (wie StatelessWidget), während der gesamte veränderliche Zustand in einem separaten State-Objekt gespeichert wird. Dies ermöglicht es Flutter, Widgets durch Vergleich nach Typ und Key wiederzuverwenden und gleichzeitig den tatsächlichen Zustand zwischen Neuaufbauten zu bewahren.
Laut Google (Flutter Architectural Overview, 2026) ist StatefulWidget optimal für Szenarien, in denen sich der Zustand während der Lebensdauer des Widgets mehr als einmal ändert: Textfelder, Animationen, Timer, Datenströme, asynchrone Ladevorgänge. Für einmalige Initialisierung ist StatelessWidget ausreichend.
StatefulWidget ist obligatorisch, wenn das Widget auf externe Ereignisse reagieren muss: Button-Klicks, Abschluss von HTTP-Anfragen, Datenbankaktualisierungen, WebSocket-Abonnements. Es ist auch notwendig für Widgets mit Animationen, Textfelder mit Controllern und Komponenten, die den Fokus verwalten. Wenn ein Widget nur Daten anzeigt und keine Ereignisse erzeugt, verwenden Sie StatelessWidget.
StatefulWidget besteht aus zwei Klassen: dem StatefulWidget selbst (leicht, unveränderlich) und State (schwer, veränderlich). Das Framework erstellt State über die createState()-Methode, die beim Einfügen in den Baum einmal aufgerufen wird. State erhält über die Eigenschaft widget eine Referenz auf das Widget und kann zu jedem Zeitpunkt des Lebenszyklus auf dessen Felder zugreifen.
Der Lebenszyklus von StatefulWidget besteht aus sechs Hauptphasen, die jeweils eine überschreibbare Methode zur Ausführung spezifischer Aufgaben bereitstellen. Das Verständnis dieser Phasen ist für eine ordnungsgemäße Ressourcenverwaltung und die Vermeidung von Speicherlecks von entscheidender Bedeutung.
createState ist die erste Methode des Lebenszyklus, die aufgerufen wird, wenn StatefulWidget in den Baum eingefügt wird. Sie muss eine neue State-Instanz zurückgeben, die mit diesem Widget verbunden ist. Diese Methode wird während der gesamten Lebensdauer des Elements genau einmal aufgerufen. Es ist wichtig, hier keine schweren Operationen durchzuführen — createState sollte so leicht wie möglich sein.
initState wird unmittelbar nach der Erstellung von State aufgerufen, vor dem ersten UI-Aufbau. Hier werden ausgeführt: Initialisierung von Controllern (TextEditingController, AnimationController), Abonnieren von Datenströmen (StreamSubscription), Einrichten von Timern und anfängliche Feldinitialisierung. Laut Flutter-Dokumentation (Flutter.dev, 2026) darf BuildContext.of() in initState nicht aufgerufen werden — der Baum ist noch nicht vollständig montiert.
didChangeDependencies wird nach initState und jedes Mal aufgerufen, wenn sich InheritedWidget-Abhängigkeiten ändern. Dies ist ein geeigneter Ort, um MediaQuery.of(context) aufzurufen oder Theme zu abonnieren — Werte, die sich während der Laufzeit der Anwendung ändern können. Wenn ein Widget InheritedWidget verwendet, sollte die Initialisierungslogik hier und nicht in initState sein.
build ist die Hauptmethode, die den Widget-Baum zurückgibt. Sie wird nach initState, nach didChangeDependencies und nach jedem setState aufgerufen. didUpdateWidget wird aufgerufen, wenn der Elternteil neu aufbaut und ein StatefulWidget mit neuen Parametern übergibt. Hier können alte und neue Widget-Felder verglichen und bei Bedarf der Zustand aktualisiert werden.
dispose ist die letzte Phase des Lebenszyklus. Hier werden alle Ressourcen freigegeben: Stream-Abonnements gekündigt, Controller entfernt, Timer abgebrochen. Das Unterlassen von dispose führt zu Speicherlecks. Nach dispose gilt State als tot — der Aufruf von setState darin löst eine Ausnahme aus.
Der Funktionsmechanismus von StatefulWidget basiert auf dem koordinierten Zusammenwirken von drei Entitäten: Widget (leichte Beschreibung), Element (Zwischenschicht) und State (Datenspeicher). Wenn Flutter in der Beschreibung auf ein StatefulWidget stößt, erstellt es ein StatefulElement, das createState aufruft und eine Referenz auf das State-Objekt speichert. Wenn der Elternteil neu aufbaut, vergleicht Flutter das neue Widget mit dem aktuellen Element — wenn Typ und Key übereinstimmen, wird das Element aktualisiert und der State bleibt gleich.
Der Zustand wird nur durch den Aufruf von setState geändert, der dem Framework mitteilt, dass ein Neuaufbau erforderlich ist. Es ist wichtig zu verstehen: setState ändert den Zustand nicht automatisch — es markiert das Widget lediglich als „schmutzig“. Der Entwickler aktualisiert die State-Felder unabhängig im Callback, der an setState übergeben wird. Nach Abschluss des Callbacks ruft Flutter build auf und aktualisiert die UI.
Laut dem Dart/Flutter-Team (Dart Language Specification, 2026) stellt diese Trennung sicher, dass alle Zustandsänderungen synchron vor dem Aufruf von build erfolgen, wodurch die Situation vermieden wird, dass die UI teilweise aktualisierte Daten anzeigt. Dies ist ein wichtiger Mechanismus zur Konsistenz der Oberfläche in Flutter.
Betrachten wir einen einfachen StatefulWidget — einen Button-Klick-Zähler. Er demonstriert das grundlegende Muster: Erstellen von State, Initialisieren eines Feldes in initState, Ändern über setState:
class CounterScreen extends StatefulWidget {
const CounterScreen({super.key});
@override
State<CounterScreen> createState() => _CounterScreenState();
}
class _CounterScreenState extends State<CounterScreen> {
int _count = 0;
void _increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Text('Count: $_count'),
ElevatedButton(
onPressed: _increment,
child: const Text('Increment'),
),
],
);
}
}
Ein Beispiel mit asynchronem Datenladen und Lebenszyklusverwaltung. StatefulWidget lädt Daten aus dem Netzwerk und zeigt den Ladezustand an:
class UserProfilePage extends StatefulWidget {
final String userId;
const UserProfilePage({super.key, required this.userId});
@override
State<UserProfilePage> createState() => _UserProfilePageState();
}
class _UserProfilePageState extends State<UserProfilePage> {
UserModel? _user;
bool _isLoading = true;
@override
void initState() {
super.initState();
_loadUser();
}
Future<void> _loadUser() async {
final user = await UserService.fetchUser(widget.userId);
setState(() {
_user = user;
_isLoading = false;
});
}
@override
Widget build(BuildContext context) {
if (_isLoading) return const CircularProgressIndicator();
return Text('Hallo, ${_user!.name}');
}
}
Im zweiten Beispiel ist wichtig zu beachten: initState startet einen asynchronen Vorgang, aber die Methode selbst ist nicht asynchron. Die Asynchronität wird über async/await innerhalb einer separaten Methode _loadUser implementiert, die den Zustand nach Abschluss der Anfrage über setState aktualisiert. Dieser Ansatz stellt sicher, dass das Widget vor dem Empfang der Daten korrekt den Ladeindikator anzeigt.
Die Wahl zwischen StatefulWidget und StatelessWidget ist nicht nur eine Frage des Vorhandenseins von Zustand. StatefulWidget bietet einen vollständigen Lebenszyklus mit den Methoden initState, didChangeDependencies, didUpdateWidget und dispose, die für die Arbeit mit Controllern, Animationen und Streams erforderlich sind. StatelessWidget hingegen hat diese Methoden nicht und ist für das Framework immer leichter.
Die Empfehlung des Flutter-Teams (Flutter docs, 2026) ist, die Anzahl der StatefulWidgets in einer Anwendung zu minimieren, indem der Zustand im Baum nach oben verschoben wird (State Hoisting) oder Lösungen zur Zustandsverwaltung (Riverpod, Bloc, Provider) verwendet werden. Jeder StatefulWidget erstellt ein State-Objekt, das lebt, bis das Element entfernt wird — je mehr solcher Widgets, desto höher die Speicherbelastung.
| Kriterium | StatefulWidget | StatelessWidget |
|---|---|---|
| Zustand | Veränderlich | Unveränderlich |
| Lebenszyklus | 6 Phasen | Nur build |
| State-Objekt | Separat erstellt | Nicht erforderlich |
| setState | Verfügbar | Nicht verfügbar |
| Abonnements | initState/dispose | Nicht unterstützt |
| const-Konstruktor | Eingeschränkt | Voll unterstützt |
| Speicherverbrauch | Höher | Niedriger |
StatefulWidget benötigt aufgrund der Notwendigkeit, ein State-Objekt zu erstellen und zu verwalten, mehr Ressourcen als StatelessWidget. Die korrekte Verwendung von StatefulWidget führt jedoch nicht zu Leistungsproblemen, wenn einige Regeln beachtet werden. Erstens vermeiden Sie tiefe Verschachtelungen von StatefulWidget — jede Ebene fügt dem Baumdurchlauf Overhead hinzu. Zweitens teilen Sie komplexe StatefulWidgets in mehrere einfache auf, die jeweils für ihren eigenen Teil des Zustands verantwortlich sind.
Laut der Flutter Performance-Untersuchung (Flutter.dev, Februar 2026) ist die häufigste Ursache für FPS-Einbrüche der Aufruf von setState in einem Eltern-Widget, das alle Nachkommen neu aufbaut, einschließlich StatelessWidgets, die ihre Anzeige nicht geändert haben. Die Lösung besteht darin, den veränderlichen Teil der UI in ein separates StatefulWidget zu extrahieren, sodass setState nur die minimal notwendigen Widgets neu aufbaut.
Die Verwendung von const innerhalb von State ist eine weitere wichtige Technik. Wenn untergeordnete Widgets als const deklariert werden, baut Flutter sie beim Aufruf von setState im Elternteil nicht neu auf. Dies reduziert die Belastung des Frameworks und verkürzt die Frame-Renderzeit.
Jeder setState-Aufruf löst einen vollständigen Widget-Neuaufbau aus. Wenn sich der Zustand mit hoher Frequenz ändert (z. B. Animation oder Datenstrom), erwägen Sie die Verwendung von AnimatedBuilder, ValueListenableBuilder oder StreamBuilder anstelle des manuellen Aufrufs von setState. Diese Widgets optimieren den Neuaufbau, indem sie nur den Teil der UI aktualisieren, der sich tatsächlich geändert hat.
Der erste häufige Fehler mit StatefulWidget ist der Aufruf von setState nach dispose. Wenn ein Widget aus dem Baum entfernt wird, gilt State als tot, und jeder setState-Aufruf löst eine Ausnahme „setState called after dispose“ aus. Dies geschieht am häufigsten, wenn ein asynchroner Vorgang nach dem Entfernen des Widgets abgeschlossen wird. Die Lösung besteht darin, das mounted-Flag vor dem Aufruf von setState zu überprüfen oder asynchrone Vorgänge in dispose abzubrechen.
Der zweite Fehler ist die Durchführung schwerer Berechnungen in der build-Methode. Da build bei jedem setState und bei jedem Neuaufbau des Elternteils aufgerufen wird, sollten alle Berechnungen so leicht wie möglich sein. Wenn ein ressourcenintensiver Vorgang erforderlich ist, verschieben Sie ihn in einen separaten Isolate oder cachen Sie das Ergebnis in einem State-Feld.
Der dritte Fehler ist das Unterlassen des Aufrufs von super.initState() und super.dispose(). Beim Überschreiben dieser Methoden muss der Entwickler die Elternimplementierung aufrufen. Andernfalls kann das Framework den Element-Zustand nicht richtig verwalten, was zu schwer verfolgbaren Fehlern führt.
mountedsuper.initState() und super.dispose() aufzurufenHäufig gestellte Fragen
StatefulWidget kann seinen Zustand über setState ändern, hat einen Lebenszyklus (initState, dispose) und erstellt ein separates State-Objekt. StatelessWidget kann den Zustand nicht ändern und hat keine Lebenszyklusmethoden — es zeigt lediglich die übergebenen Daten an.
createState wird für jede StatefulElement-Instanz genau einmal aufgerufen. Selbst wenn der Elternteil mehrmals neu aufbaut, wird createState nicht aufgerufen, solange sich Typ und Key des Widgets nicht ändern — das vorhandene State-Objekt wird verwendet.
Ressourcen werden nicht freigegeben: Controller arbeiten im Hintergrund weiter, Stream-Abonnements bleiben aktiv, Timer werden nicht abgebrochen. Dies führt zu Speicherlecks und kann setState-Aufrufe nach dispose verursachen, was eine Ausnahme auslöst.
Ja, der Konstruktor von StatefulWidget kann const sein. Dies bietet jedoch nicht denselben Vorteil wie bei StatelessWidget — das State-Objekt wird beim ersten Einfügen trotzdem erstellt. const betrifft nur das Widget selbst (den leichten Wrapper), nicht den State.
didUpdateWidget wird aufgerufen, wenn der Elternteil ein StatefulWidget mit neuen Parametern übergibt. Dies ist notwendig, um den Zustand mit neuen Daten zu synchronisieren — zum Beispiel, wenn sich die userId in den Parametern geändert hat, muss das Profil des neuen Benutzers geladen werden.
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