Skip to main content

Grundlegendes zu Flutter

πŸ”„Β Async/Await - VollstΓ€ndige ErklΓ€rung

Das Problem: Warum ist Dateiarbeit langsam?

Stell dir vor, du machst eine Pizza:

text
SYNCHRON (blockierend - FALSCH fΓΌr Dateien): β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1. Pizza in den Ofen (15 Min) β”‚ β”‚ ← Der PizzabΓ€cker WARTET hier! β”‚ β”‚ ← Kann nichts anderes machen! β”‚ β”‚ β”‚ β”‚ 2. Pizza rausnehmen β”‚ β”‚ 3. NΓ€chste Pizza machen β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Resultat: Sehr ineffizient!
text
ASYNCHRON (nicht-blockierend - RICHTIG fΓΌr Dateien): β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ 1. Pizza in den Ofen (15 Min) β”‚ β”‚ ← Der PizzabΓ€cker WARTET NICHT! β”‚ β”‚ β”‚ β”‚ 2. Macht wΓ€hrenddessen Pizza 2 (parallel) β”‚ 3. Macht Pizza 3 β”‚ β”‚ 4. Bekommt Signal: "Pizza 1 ist fertig!" β”‚ 5. Holt Pizza 1 raus β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ Resultat: Sehr effizient!

Code-Beispiel: Sync vs Async

❌ SYNCHRON (Falsch für Dateien):

dart
void main() { print('Start'); // Annahme: Datei braucht 2 Sekunden final file = File('data/users.json'); final content = file.readAsStringSync(); // ← BLOCKIERT! print('Datei gelesen: $content'); print('Fertig'); } // Output: // Start // [warte 2 Sekunden... nichts lΓ€uft!] // Datei gelesen: ... // Fertig // Die App war 2 Sekunden "eingefroren"!

Problem:Β WΓ€hrend die App wartet, kann sie NICHTS anderes machen!


βœ…Β ASYNCHRON (Richtig fΓΌr Dateien):

dart
void main() async { // ← main() wird async! print('Start'); final file = File('data/users.json'); final content = await file.readAsString(); // ← BLOCKIERT NICHT! print('Datei gelesen: $content'); print('Fertig'); } // Output: // Start // [warte 2 Sekunden... aber die App lΓ€uft weiter!] // Datei gelesen: ... // Fertig // Die App war NICHT eingefroren!

Vorteil:Β Die App kann wΓ€hrend des Wartens andere Dinge machen!


🎯 Was bedeuten die Keywords?

Keyword Bedeutung Beispiel
async "Diese Methode ist langsam, kann warten" Future<String> getData() async { ... }
await "Warte hier, bis Ergebnis kommt" final data = await loadFile();
Future<T> "Ein Ergebnis vom Typ T kommt spΓ€ter" Future<int> getAge() { ... }

πŸ“ŠΒ Visualisierung: Der Fluss von Async/Await

text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Code ausfΓΌhren β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ await StorageService.loadUsers() β”‚ β”‚ ↓ Dart sagt: "Das dauert, gib mir ein Future" β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β–Ό (Hauptprogramm) β–Ό (Datei laden im Hintergrund) (kΓΆnnte hier etwas loadUsers() arbeitet anderes machen) in Ruhe... β”‚ β”‚ β”‚ [Datei ist geladen!] β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ loadedUsers hat jetzt den Wert! β”‚ β”‚ Programm fΓ€hrt fort: print('Fertig') β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ§ͺΒ Praktisches Beispiel: Async testen

ErstelleΒ bin/async_demo.dart:

dart
import 'dart:io'; // Beispiel 1: Synchrone Funktion (NICHT async) void syncFunction() { print('Sync Start'); sleep(Duration(seconds: 2)); // Blockiert die App! print('Sync Ende (nach 2 Sekunden)'); } // Beispiel 2: Asynchrone Funktion (mit async/await) Future<void> asyncFunction() async { print('Async Start'); await Future.delayed(Duration(seconds: 2)); // Blockiert NICHT! print('Async Ende (nach 2 Sekunden)'); } // Beispiel 3: Mehrere Async-Funktionen (parallel!) Future<void> multipleAsync() async { print('\n=== Mehrere Async-Tasks parallel ==='); // Alle 3 starten gleichzeitig! final task1 = doTask('Task 1', 1); final task2 = doTask('Task 2', 2); final task3 = doTask('Task 3', 3); // Warte auf alle await Future.wait([task1, task2, task3]); print('Alle Tasks fertig!'); } Future<void> doTask(String name, int seconds) async { print('$name startet...'); await Future.delayed(Duration(seconds: seconds)); print('$name fertig!'); } void main() async { print('=== SYNCHRON (blockierend) ==='); syncFunction(); // Freezt die App! print('\n=== ASYNCHRON (nicht-blockierend) ==='); await asyncFunction(); // App lΓ€uft weiter! await multipleAsync(); }

Starte das Programm:

bash
dart bin/async_demo.dart

Erwartete Ausgabe:

text
=== SYNCHRON (blockierend) === Sync Start Sync Ende (nach 2 Sekunden) === ASYNCHRON (nicht-blockierend) === Async Start Async Ende (nach 2 Sekunden) === Mehrere Async-Tasks parallel === Task 1 startet... Task 2 startet... Task 3 startet... Task 3 fertig! Task 2 fertig! Task 1 fertig! Alle Tasks fertig!

Beobachtung:Β Task 3 endet zuerst (nur 1 Sekunde), obwohl sie nicht zuerst startete! Das zeigt, dass sieΒ parallelΒ laufen! πŸš€


πŸŽ“Β Die 3 ZustΓ€nde eines Future

EinΒ FutureΒ hat immer einen von 3 ZustΓ€nden:

text
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Future Status β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ 1. PENDING (wartet noch) β”‚ β”‚ await loadUsers() β”‚ β”‚ ↓ (Datei wird gelesen...) β”‚ β”‚ β”‚ β”‚ 2. COMPLETED (fertig!) β”‚ β”‚ ↓ (Datei komplett gelesen) β”‚ β”‚ loadedUsers = [User(...), ...] β”‚ β”‚ β”‚ β”‚ 3. ERROR (Fehler!) β”‚ β”‚ ↓ (Datei nicht gefunden) β”‚ β”‚ catch (e) { print(e); } β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

⚠️ Wichtige Regeln:

Regel 1:Β Du kannstΒ nurΒ awaitΒ innerhalb vonΒ asyncΒ FunktionenΒ nutzen!

dart
// βœ… RICHTIG: Future<void> myFunction() async { await Future.delayed(Duration(seconds: 1)); } // ❌ FALSCH: void myFunction() { await Future.delayed(Duration(seconds: 1)); // ERROR! }

Regel 2:Β Wenn duΒ awaitΒ brauchst, muss die FunktionΒ asyncΒ sein!

dart
// βœ… RICHTIG: void main() async { // ← main() wird async! await StorageService.loadUsers(); } // ❌ FALSCH: void main() { await StorageService.loadUsers(); // ERROR! }

Β 

Regel 3:Β asyncΒ macht deine Funktion automatisch zu einemΒ Future!

Future<String> getData() async { // ← Gibt automatisch Future<String> zurΓΌck! 
  return "Daten"; } // Ist gleichbedeutend mit: 

Future<String> getData2() { // ← Musst du manuell Future sagen 
  return Future.value("Daten"); }

🧠 Kurze Analogie:

Synchron: 
Du: "Barista, mach mir einen Kaffee" 
Barista: "Ja, warte hier... [5 Minuten warten]... Fertig!" 
Du: "Okay, danke!" ← Du konntest nur herumsitzen! 

Asynchron: 
Du: "Barista, mach mir einen Kaffee" (mit Future-Ticket) 
Barista: "Ja, kein Problem, ich ruf dich auf!" 
Du: "Gut, ich setz mich hin und lies Zeitung" ← Du machst etwas anderes! [5 Minuten spΓ€ter] 
Barista: "Dein Kaffee ist fertig!" (Future resolved!) 
Du: "Danke!" ← Du warst nicht blockiert!

Methoden und Klassen

Eine typische Funktion in Dart besteht aus dem RΓΌckgabewert, dem Namen, optionalen Parametern und dem FunktionskΓΆrper.

Aufbau einer Funktion

dart
Rueckgabewert funktionsName(Parameter) {
  // FunktionskΓΆrper
  return wert; // nur wenn Rueckgabewert nicht void ist
}

Beispiel:

dart
int addiere(int a, int b) {
  return a + b;
}

Aufbau einer Klasse

Eine Klasse bΓΌndelt Werte (Felder), einen Konstruktor und Methoden.

dart
class Auto {
  // Felder
  final String marke;
  int kilometerstand;

  // Konstruktor
  Auto(this.marke, this.kilometerstand);

  // Methode
  void fahre(int kilometer) {
    kilometerstand += kilometer;
  }

  // Eine Methode mit RΓΌckgabewert
  String beschreibung() {
    return 'Marke: $marke, Kilometerstand: $kilometerstand';
  }
}

Nutzung der Klasse

dart
void main() {
  final auto = Auto('Tesla', 0);   // Konstruktor
  auto.fahre(120);                 // Methode
  print(auto.beschreibung());      // Methode mit RΓΌckgabewert
}

So siehst du den typischen Aufbau: Felder speichern den Zustand, der Konstruktor initialisiert ihn, und Methoden Γ€ndern oder lesen ihn aus.