Nun geht es in die vollen, denn heute bauen wir unsere erste richtige Logik. Am Ende des vierten Teils dieser Tutorialreihe soll die initiale Logik zum Start der App und die RSS Feed Logik implementiert sein.
Zur Umsetzung erstellen wir den MainBloc (lib/main/main_bloc.dart open_in_new), der die Datenbank lädt und später z.B. das Laden der Konfiguration übernehmen kann. Sobald dieser Vorgang abgeschlossen ist, sollen alle RssFeed Objekte mit Hilfe des FeedListBloc (lib/feed_list/feed_list_bloc.dart open_in_new) aus der Datenbank geladen werden.
Damit die Datenbank auch mit Inhalt gefüllt ist, soll es über die UI möglich sein einen neuen Feed anzulegen. Sowohl für das Laden der RssFeeds, wie auch für das Hinzufügen wird der FeedListBloc genutzt. Außerdem erstellen wir geeignete Widgets zur Darstellung der Liste (lib/feed_list/feed_list.dart open_in_new) und des Formulars (lib/feed_list/feed_list_change.dart open_in_new), wobei letzteres im nächsten Teil der Reihe umgesetzt wird.
In diesem Zuge habe ich auch eine kleine Umbenennung vorgenommen, denn unser RssList Widget (nun FeedList Widget) und alle damit verwandten Klassen, befinden sich nun im FeedList Kontext open_in_new (Namen und Pakete). Dieser Name gefiel mir einfach besser und ist gleichzeitig kürzer und deutlicher. Die Bezeichnung für den Typ bleibt allerdings unverändert bei RssFeed.
Damit das Verstehen der folgenden Schritte leichter fällt, beginne ich mit einem schnellen Einblick in das BloC Konzept. Ich empfehle euch allerdings die offizielle Dokumentation open_in_new zum Thema anzuschauen, wenn ihr das Ganze aktiv nutzen wollt. Sie ist übersichtlich, gut gemacht und bietet außerdem diverse gute Beispiele.
BloC oder auch Business Logic Components ist mein aktuell favorisierter Weg, um Logik von UI und wiederum von Daten zu trennen. Dafür wird sehr intensiv auf das Konzept von Streams open_in_new gesetzt. Ein BloC interagiert immer mit zwei Streams, einem für den Input (Events) und einen für den Output (States), dabei sollte jedes Event zu mindestens einem passenden State führen. Im konkreten Library Kontext wird dafür die mapEventToState() open_in_new Methode genutzt. Sofern ihr einen BloC erstellt und Bloc open_in_new erweitert, müsst ihr sowohl die akzeptierten Events dieses BloC, wie auch die dazugehörigen States angeben. Diese definiert man meist in einer gesonderten Datei, wodurch ein übersichtlicher klarer Rahmen von erlaubten Eingaben und Ausgaben definiert wird.
Events können von der UI, z.B. durch einen Tap auf einen Button, kommen oder aber von anderen BloCs, bzw. tieferliegenden Komponenten. States werden vom BloC erzeugt und meist von der UI verarbeitet und führen zu automatischen Anpassungen von selbiger. Allerdings können auch andere BloCs auf State Änderungen hören und entsprechend Aktionen durchführen. Es ist außerdem erlaubt im Laufe der Verarbeitung mehrere States zu liefern. So macht es bei längeren Aktionen zum Beispiel Sinn, am Anfang einen Loading State zu übergeben und nach Abschluss einen State der die finalen Daten zurückgibt.
Entsprechend gibt es verschiedene Quellen für Events und verschiedene Ziele für States, auch mehrere gleichzeitig sind möglich. Streams bieten hier viele Freiheiten und Flexibilität, es ist allerdings extrem wichtig alles ordentlich zu dokumentieren und klare Flows zu etablieren. Denn mit großer Flexibilität kommt sonst großes Chaos.