Grundlegendes zu Flutter
πΒ Async/Await - VollstΓ€ndige ErklΓ€rung
Das Problem: Warum ist Dateiarbeit langsam?
Stell dir vor, du machst eine Pizza:
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!
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):
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):
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
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β 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:
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:
dart bin/async_demo.dart
Erwartete Ausgabe:
=== 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:
βββββββββββββββββββββββββββββββββββββββ
β 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!
// β
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!
// β
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
Rueckgabewert funktionsName(Parameter) {
// FunktionskΓΆrper
return wert; // nur wenn Rueckgabewert nicht void ist
}
Beispiel:
int addiere(int a, int b) {
return a + b;
}
Aufbau einer Klasse
Eine Klasse bΓΌndelt Werte (Felder), einen Konstruktor und Methoden.
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
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.
No Comments