Rx = Reactive Extensions

Rx

Reactive Extensions (Rx) ist ein Programmierparadigma, das auf dem Observer-Pattern basiert und es ermöglicht, asynchrone und ereignisbasierte Programmierung auf eine konsistente und leicht verständliche Weise zu behandeln.

In Flutter wird Rx Dart häufig verwendet, um reaktive Programmierkonzepte zu implementieren, insbesondere wenn es um die Verwaltung von Streams und Ereignissen geht. Mit Rx Dart können Entwickler auf elegante Weise auf Ereignisse reagieren und mit Streams arbeiten, indem sie Funktionen wie map, filter, merge und andere verwenden, um Datenströme zu manipulieren.

Es gibt verschiedene Pakete und Bibliotheken in Dart, die Rx Dart implementieren, und Entwickler können diese verwenden, um reaktive Programmiermuster in ihren Flutter-Anwendungen zu integrieren. Rx Dart ist nicht Teil des Flutter-Frameworks, sondern eine separate Bibliothek.

Ein einfaches Beispiel in Dart mit dem rxdart-Paket für Flutter vom GPT:

import ‚package:flutter/material.dart‘;
import ‚package:rxdart/rxdart.dart‘;

void main() {
  runApp(MyApp());
}

class CounterBloc {
  final BehaviorSubject<int> _counterSubject = BehaviorSubject<int>.seeded(0);

  Observable<int> get counterStream => _counterSubject.stream;

  void incrementCounter() {
    _counterSubject.add(_counterSubject.value + 1);
  }

  void dispose() {
    _counterSubject.close();
  }
}

class MyApp extends StatelessWidget {
  final CounterBloc _counterBloc = CounterBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        appBar: AppBar(
          title: Text(‚Rx Dart Beispiel‘),
        ),
        body: Center(
          child: StreamBuilder<int>(
            stream: _counterBloc.counterStream,
            builder: (context, snapshot) {
              if (snapshot.hasData) {
                return Text(‚Counter: ${snapshot.data}‘);
              } else {
                return Text(‚Loading…‘);
              }
            },
          ),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () {
            _counterBloc.incrementCounter();
          },
          child: Icon(Icons.add),
        ),
      ),
    );
  }

  @override
  void dispose() {
    _counterBloc.dispose();
    super.dispose();
  }
}
 

In diesem Beispiel verwendet der CounterBloc das BehaviorSubject ausrxdart, um den aktuellen Counter-Wert zu speichern und als Stream bereitzustellen. Die Benutzeroberfläche reagiert auf Änderungen des Streams und aktualisiert den dargestellten Counter-Wert. Der Counter wird jedes Mal erhöht, wenn auf den FloatingActionButton geklickt wird. Beachten Sie auch die Verwendung der dispose-Methode, um sicherzustellen, dass der BLoC korrekt freigegeben wird.

Bild als Background anbinden

Bild als Background anbinden

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Container(
    decoration: BoxDecoration(
        image: DecorationImage(
            image: AssetImage('assets/background_image.jpg'), // Pfad zu Ihrem Bild
            fit: BoxFit.cover, // Anpassen, um den Bildschirm zu füllen
            ),
        ),
        child: // Ihr weiterer Inhalt hier
        Center(
             child: Text('Ihr Inhalt hier',
            style: TextStyle(color: Colors.white),
        ),
    ),
),

Projekt erstellen

Projekt erstellen

  1. VS Code öffnen
  2. Commando-Zeile öffnen –> „CTRL+SHIFT+P“ (Mac users replace CTRL with CMD)
  3. „Flutter“ eintippen
  4. Die Option „Flutter: New Project“ auswählen
  5. „Application“-Option aus der Liste auswählen
  6. Ordner für Projekt auswählen –> Enter
  7. Namen für Projekt geben (kleine Buchstaben und Unterstriche) –> Enter

Syntax des StatefulWidgets

Syntax des StatefulWidgets

Im body eines Stateful Widgets hat es einen Konstruktor und erzeugt einen State-Objekt.

Wenn ein Widget-Obkekt erzeugt wird ( über WidgetName ),

erst wird sein Konstruktor aufgerufen, es zu initiieren.

Dann erzeugt der Stateful Widget einen State-Objekt.

Sobald ein State-Objekt erzeugt wird, bekomt unser Widget damit Eigenschaften und Methoden, mit deren wir im body des Widget-State-Objektes arbeiten können. Die wichtigsten Eigenschaften sind context und widget. Dank context sehen wir unseren Widget im Widget-Baum und können verschiedene Methoden des State-Objektes innerhalb seines body nutzen. Die Eigenschaft widget ermöglicht uns Informationen über unser Widget abzufragen.

Ein State-Objekt verfügt über mehrere Methoden, die für bestimmte Zwecke gedacht sind.

Implizit wird eine Methode initState() – immer – aufgerufen, damit der State-Objekt initiiert und einen context im Widget-Baum erhält. (Ohne context kann die Methode build() nicht funktionieren, also kein Element wird gezeichnet.)

Die Methode build() zeichnet ein Element (entsprechend unserem Widget) auf dem Bildschirm. Diese Methode muss immer im body des Stateful Widget sein, weil wir da weitere Komposition-Widgets platzieren.

Die Hauptaufgabe eines Stateful Widgets ist ein State-Objekt zu erzeugen; Es ist nur ein leeres Box, der weder Elemente zeichnen kann, noch ein State beinhaltet – das Alles kann das State-Objekt, das von Stateful Widget erzeugt wurde.

Eigenes Flutter-Widget

Eigenes Flutter-Widget

In der Quellcode können Sie sogar ein eigenes Widget definieren.

In diesem Beispiel habe ich ein eigenes Widget von dem „Container“-Widget geerbt, deswegen kann ich die Eigenschaften (Parameter) wie alignment oder width von „Container“-Widget benutzen.

Mein Widget soll aber bestimmte Argumente einnehmen: text und color, deswegen stehen die als Patrameter in Klammern nach dem Namen. Diese Parameter müssen in der Quellcode davor als Variablen mit entsprechenden Typ deklariert werden.

Es ist wichtig bei der Vergabe der Widget-Namen zu beachten, dass es lesbar und verständlich ist, hier ist es „buildText“, ich konnte es auch „buildColoredText“ benennen.

Nun habe ich ein Widget buildText(), mit dem ich ein Box mit farbigen Text in auf einem Screen in meiner App darstellen kann.

Anatomie des Widgets

Anatomie des Widgets

Jeder Widget besitzt den optionalen* Parameter key. Der „Key“ bestimmt, dass jeder erzeugter Widget eine konkrete (unique) Stelle im Elementen-Baum annimmt. 

*ein Wert an den Parameter key muss nicht explizit zuweisen werden, es wird implizit mit dem Widget erzeugt.

Widgets besitzen eigene individuelle Kombination an Parameter, z.B. hier ein „Center“-Widget hat key, widthFactor, heightFactor und child Parameter:

Einige Widgets stellen mit sich ein einzelner Fall eines Stamm-Widgets, z.B. der Widget „Center“ ererbt von seinem Parent-Widget „Align“ Dafault-Parameter „alignment“.

Syntax der Flutter-Widgets

Die Code-Snippets Oben beziehen sich auf die Quellcode für den Flutter-Framework (dort werden Klassen für alle Widgets in Dart geschrieben).

Wenn Sie die Quellcode für Ihre Flutter App in einem Editor schreiben, sieht die Syntax eines „Center“-Widgets folgendenweise aus:

Wenn mit dem Mauszeiger auf den Namen eines Widgets gehen, erscheint un einem Fensterchen über den Widgetsnamen die „Anatomie“ dieses Widgets mit aufgelisteten Parameter (Eigenschaften), die Sie für diesen Widget nehmen können.

Asynchronous Programming / EN

Asynchronous Programming allows your app to complete time-consuming tasks, such as retrieving an image from the web, or writing some data to a web server, while running other tasks in parallel and responding to the user input. This improves the user experience and the overall quality of your software. 

In Dart and Flutter, you can write asynchronous code leveraging Futures, and the async/await pattern: these patterns exist in most modern programming languages, but Flutter also has a very efficient way to build the user interface asynchronously using the FutureBuilder class. 

Using a Future 

When you write your code, you generally expect your instructions to run sequentially, one line after the other. For instance, let’s say you write the following: 

int x = 5; int y = x * 2; 

You expect the value of y to be equal to 10 because the instruction int x = 5 completes before the next line. In other words, the second line waits for the first instruction to complete before being executed. 

unresponsive until the task is completed 

Asynchronous operations do not stop the main line of execution, and therefore they allow the execution of other tasks before completing. 

The diagram shows how the main execution line, which deals with the user interface, can call a long-running task asynchronously without stopping to wait for results, and when the long-running task completes, it returns to the main execution line, which can handle it.

Dart is a single-threaded language, but despite this, you can use asynchronous programming patterns to create reactive apps.

to perform asynchronous operations you can use the Future class
Some use cases where an asynchronous approach is recommended include retrieving data from a web service, writing data to a database, finding a device’s coordinates, or reading data from a file on a device. Performing these tasks asynchronously will keep your app responsive.
Some use cases where an asynchronous approach is recommended include retrieving data from a web service, writing data to a database, looking up device coordinates, or reading data from a file on the device. Performing these tasks asynchronously will ensure your application is responsive.