Wichtige Begriffe für Dart und Flutter-Entwickler

Als Flutter-Entwickler ist es entscheidend, die Terminologie der Programmiersprache Dart sowie des Flutter-Frameworks zu verstehen. Mit diesem Beitrag lernst du nicht nur die Bedeutungen der Begriffe, sondern auch, wie du sie in der Praxis anwendest. Ziel ist es, diese Begriffe aktiv in Gesprächen und im Code-Alltag zu nutzen.

Grundlagen

  • Annotation @JsonSerializable
  • Factory Constructor
  • Null-Safety
  • Future
  • Getter
  • => (Fat Arrow)
  • Enum

Flutter-spezifisch

  • Interface: implements
  • Widget
  • State
  • BuildContext
  • InheritedWidget
  • Stream

OOP und Typisierung

  • Private Felder in Dart
  • Listen und List.filled
  • Hot Reload

Grundlagen

Annotation @JsonSerializable

@JsonSerializable ist eine Annotation, die angibt, dass eine Klasse in JSON-Daten umgewandelt werden kann. Es gehört zum Paket json_annotation und erleichtert die Serialisierung und Deserialisierung.

Bedeutung: JSON-Daten sind ein universelles Format für den Datenaustausch. Mit @JsonSerializable können Klassen einfach in JSON konvertiert und daraus erstellt werden. Es spart Zeit und reduziert Fehler bei der manuellen Kodierung.

Beispiel:

@JsonSerializable()
class User {
  final String name;
  final int age;

  User(this.name, this.age);

  factory User.fromJson(Map<String, dynamic> json) => _$UserFromJson(json);
  Map<String, dynamic> toJson() => _$UserToJson(this);
}

In diesem Fall generiert der Code-Generator Methoden wie toJson und fromJson, um Instanzen der Klasse User in JSON umzuwandeln und umgekehrt.


Factory Constructor

Ein Konstruktor, der eine Instanz der Klasse zurückgibt, ohne zwingend eine neue Instanz zu erstellen. Dies ist nützlich, um kontrollierten Zugriff auf die Erstellung von Objekten zu ermöglichen.

Oder mit anderen Worten: Ein factory-Konstruktor erstellt eine Instanz einer Klasse, muss aber nicht zwingend ein neues Objekt erstellen. Er kann z. B. bestehende Instanzen zurückgeben.

Bedeutung: Ein Factory Constructor wird häufig verwendet, um Caching oder Designmuster wie Singleton umzusetzen.

Beispiel:

class Logger {
  static final Logger _instance = Logger._internal();
  factory Logger() => _instance;
  Logger._internal();
}

Hier stellt Logger sicher, dass es nur eine Instanz gibt (Singleton-Muster).


Null-Safety

Ein Konzept in Dart, das sicherstellt, dass Variablen nicht null sein können, es sei denn, dies wird explizit erlaubt.

Bedeutung: Null-Safety reduziert Laufzeitfehler durch NullPointerExceptions erheblich.

Beispiel:

String? nullableString; // Kann null sein
String nonNullableString = 'Hello'; // Kann nicht null sein

Future

Ein Future ist ein Objekt in Dart, das einen Wert repräsentiert, der irgendwann in der Zukunft verfügbar sein wird, oder einen Fehler, falls die Operation fehlschlägt.

Bedeutung: Future wird verwendet, um asynchrone Operationen wie HTTP-Anfragen, Dateioperationen oder zeitgesteuerte Aktionen zu verwalten. Es ist ein zentraler Bestandteil der Dart-Programmierung für reaktive Apps.

Beispiel:

Future<String> fetchData() async {
  await Future.delayed(Duration(seconds: 2));
  return 'Daten geladen';
}

void main() async {
  print('Laden...');
  String data = await fetchData();
  print(data);
}

In diesem Beispiel simuliert fetchData das Abrufen von Daten, und await pausiert den Code, bis das Ergebnis verfügbar ist.


Getter

Definition:
Ein Getter ist eine Methode in Dart, die wie ein Feld verwendet wird, um einen berechneten Wert bereitzustellen.

Bedeutung:
Getter sind nützlich, um die Kapselung zu gewährleisten und berechnete Eigenschaften zu erstellen, ohne dass der Nutzer erkennen muss, dass eine Berechnung stattfindet. Sie verbessern die Lesbarkeit des Codes und machen ihn übersichtlicher.

Beispiel:

class Rectangle {
  int width;
  int height;

  Rectangle(this.width, this.height);

  // Getter in Kurzform
  int get area => width * height;

  // Getter in Langform
  int get perimeter {
    return 2 * (width + height);
  }
}

void main() {
  var rect = Rectangle(10, 5);
  print("Area: ${rect.area}");        // Ausgabe: Area: 50
  print("Perimeter: ${rect.perimeter}"); // Ausgabe: Perimeter: 30
}

=> (Fat Arrow)

Definition:
Das Symbol => ist eine Kurzform für return in Dart. Es wird verwendet, um kompakte und einfache Funktionen oder Methoden zu definieren, die genau eine Anweisung enthalten.

Bedeutung:
Die =>-Syntax macht den Code kürzer und lesbarer, besonders bei Getter-Methoden oder Lambda-Ausdrücken.

Beispiel:

// Kurzform mit => für eine einfache Berechnung
int square(int x) => x * x;

// Äquivalent in Langform
int square(int x) {
  return x * x;
}

void main() {
  print(square(5)); // Ausgabe: 25
}

Enum

Ein Enum (kurz für «Enumeration») ist ein spezieller Datentyp, der eine Sammlung von konstanten Werten definiert.

Bedeutung: Enums sind nützlich, um Werte mit festen Optionen darzustellen, z. B. Tage der Woche, Zustände oder Modus-Typen. Sie verbessern die Lesbarkeit und Fehlervermeidung im Code.

Beispiel:

enum Weather { sunny, rainy, cloudy }

void main() {
  var today = Weather.sunny;
  print(today.name); // Ausgabe: sunny
}

Flutter-spezifisch

Interface: implements

Dart unterstützt keine Mehrfachvererbung, aber mit implements können Klassen Interfaces verwenden, um bestimmte Methoden und Eigenschaften zu erzwingen.

Bedeutung:
implements hilft, die Struktur von Klassen zu definieren, die spezifische Funktionalität bereitstellen müssen. Es wird häufig in Flutter verwendet, um wiederverwendbare Logik zu implementieren.

Beispiel:

abstract class Printable {
  void printInfo();
}

class User implements Printable {
  String name;

  User(this.name);

  @override
  void printInfo() {
    print('Name: $name');
  }
}

Widget

Die grundlegenden Bausteine jeder Flutter-App. Widgets sind wiederverwendbare Komponenten, die entweder statisch (z. B. Text) oder dynamisch (z. B. StatefulWidget) sein können.

Bedeutung: Widgets beschreiben die visuelle und funktionale Struktur der App.

Beispiel:

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text('Hallo Flutter!');
  }
}

Jede Flutter-App basiert auf einer Hierarchie von Widgets, die den UI-Baum bilden.


State

Eine Datenstruktur, die die aktuellen Eigenschaften eines Widgets enthält und sich während der Laufzeit ändern kann.

Bedeutung: Der Zustand eines Widgets bestimmt dessen Darstellung und Verhalten.

Beispiel:

class Counter extends StatefulWidget {
  @override
  _CounterState createState() => _CounterState();
}

class _CounterState extends State<Counter> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Text('Counter: $_counter');
  }
}

In diesem Beispiel wird setState verwendet, um den Zustand des Counters zu aktualisieren.


BuildContext

Ein Objekt, das Informationen über den Ort eines Widgets in der Widget-Hierarchie liefert. Es wird in vielen Widget-Methoden wie build oder Navigator verwendet.

Bedeutung: BuildContext erlaubt Widgets, mit der umgebenden Struktur zu interagieren.

Beispiel:

@override
Widget build(BuildContext context) {
  final theme = Theme.of(context);
  return Text('Hallo', style: theme.textTheme.headline4);
}

BuildContext ermöglicht den Zugriff auf übergeordnete Daten wie das Thema oder die Lokalisierung.


InheritedWidget

Ein InheritedWidget ist eine spezielle Art von Widget, das Daten für dessen untergeordnete Widgets bereitstellt, ohne sie explizit weiterzugeben. Änderungen an den Daten lösen automatisch eine Aktualisierung der betroffenen Widgets aus.

Bedeutung: InheritedWidget wird verwendet, um Zustandsmanagement auf niedrigem Niveau zu implementieren. Bekannte Pakete wie Provider bauen auf diesem Konzept auf.

Beispiel:

class MyInheritedWidget extends InheritedWidget {
  final int counter;

  MyInheritedWidget({required this.counter, required Widget child}) : super(child: child);

  @override
  bool updateShouldNotify(MyInheritedWidget oldWidget) {
    return oldWidget.counter != counter;
  }

  static MyInheritedWidget? of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<MyInheritedWidget>();
  }
}

void main() {
  runApp(MyInheritedWidget(
    counter: 5,
    child: Builder(
      builder: (context) {
        final inherited = MyInheritedWidget.of(context);
        return Text('Counter: ${inherited?.counter}');
      },
    ),
  ));
}

In diesem Beispiel speichert MyInheritedWidget eine Zählervariable und stellt diese seinen untergeordneten Widgets bereit. Änderungen am Zähler werden automatisch erkannt und die Benutzeroberfläche aktualisiert.


Stream

Ein Stream in Dart ist eine Abfolge von asynchronen Ereignissen, die über einen Zeitraum hinweg eintreffen. Streams können entweder «einmalig» (Single-Subscription) oder «mehrfach» (Broadcast) genutzt werden.

Bedeutung: Streams sind besonders nützlich für die Verarbeitung von Datenströmen wie Benutzereingaben, Netzwerkanfragen oder anderen wiederkehrenden Ereignissen.

Beispiel:

Stream<int> countStream() async* {
  for (int i = 1; i <= 5; i++) {
    await Future.delayed(Duration(seconds: 1));
    yield i;
  }
}

void main() {
  countStream().listen((event) {
    print('Event: $event');
  });
}

Hier erzeugt countStream eine Sequenz von Zahlen, die jede Sekunde gesendet werden. Die listen-Methode reagiert auf jedes neue Ereignis im Stream.


OOP und Typisierung

Private Felder in Dart

Ein privates Feld in Dart wird mit einem Unterstrich (_) deklariert und ist nur innerhalb der Datei sichtbar, in der es definiert ist.

Bedeutung:
Dies schützt Felder vor ungewolltem Zugriff von außen und sorgt für eine klare Trennung zwischen der internen Logik einer Klasse und ihrer öffentlichen API.

Beispiel:

class User {
  String _name; // privates Feld

  User(this._name);

  String get name => _name; // Getter für den Zugriff
}

Listen und List.filled

List.filled erstellt eine Liste mit einer festen Länge und einem Standardwert für alle Elemente.

Bedeutung:
Es ist besonders nützlich, wenn man eine Liste mit einem festen Format oder Standardwerten initialisieren muss. Vorsicht: Alle Einträge teilen sich dieselbe Instanz, wenn Objekte verwendet werden.

Beispiel:

var list = List.filled(3, 'Standardwert');
print(list); // ['Standardwert', 'Standardwert', 'Standardwert']

Hot Reload

Definition:
Hot Reload ist eine Funktion von Flutter, mit der Änderungen am Code in Echtzeit in der laufenden App angezeigt werden können, ohne sie neu starten zu müssen.

Bedeutung:
Hot Reload beschleunigt die Entwicklung erheblich, da es Entwicklern ermöglicht, Änderungen sofort zu sehen und Fehler schneller zu beheben.

Beispiel:

  1. Füge einen neuen Text in das body-Widget einer Flutter-App ein.
  2. Speichere die Datei.
  3. Schau, wie die Änderung sofort in der laufenden App angezeigt wird.


Comments

Schreiben Sie einen Kommentar

Ihre E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert