Flutter BloC Pattern 1
![]() |
Las Vegas |
Basis BloC
Es gibt verschiedene Konzepte um mit dem State umzugehen, diese stehen nicht in Konkurrenz. Es ist an dem Entwickler, sich für ein Konzept zu entscheiden, je nach den erwarteten Erfordernissen der geplanten Software.
BloC steht für Business Logic Component und ermöglicht das Handling der State's.
Es wird gerne als Pattern bezeichnet, also als Muster, mit welchem wir den Umgang mit einem State konzipieren. Die hinter BloC ist die Trennung der Präsentation (UI / StatelessWidgets) von der Logic (StatefulWidgets). Das heißt der Button, den wir in der App drücken, muss nichts darüber wissen, was nach dem drücken passiert. In einem Fall wird man vielleicht auf eine neue Seite geleitet, in einem anderen Fall wird zum Beispiel nur eine Zahl erhöht. Damit kann man diesen Button leicht wiederverwenden, ein erwünschter Effekt von BloC.
Wie funktioniert nun ein BloC ?
Ein BloC nimmt Ereignisse auf, Events, verarbeitet sie gemäß einer Logik, und gibt einen State aus. Im Falle des Button, ist das drücken das Ereignis und die Reaktion darauf, der von BloC ausgegebene State. Wie die BloC Einheit das Ereignis behandelt ist dementsprechend die Logik.
Ein einfaches Beispiel
Am Besten lernt man das Konzept hinter BloC mit "learning by doing". Als Basis für ein einfaches Beispiel nehmen wir den Boiler Code, den uns Visual Studio Code / Android Studio vorgibt. Wir implementieren einen zweiten Button. Der erste addiert, der zweite subtrahiert. Des weiteren ergänzen wir den setState Teil im Code um eine Variante für die Subtraktion.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void _incrementCounter() { | |
setState(() { | |
_counter++; | |
}); | |
} | |
void _decrementCounter() { | |
setState(() { | |
_counter--; | |
}); | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
floatingActionButton: Row( | |
mainAxisAlignment: MainAxisAlignment.end, | |
children: <Widget>[ | |
FloatingActionButton( | |
onPressed: _incrementCounter, | |
tooltip: 'Increment', | |
child: Icon(Icons.add), | |
), | |
SizedBox(width: 10.0,), | |
FloatingActionButton( | |
onPressed: _decrementCounter, | |
tooltip: 'Decrement', | |
child: Icon(Icons.remove), | |
), |
zaehler_ereignis.dart und zaehler_bloc.dart
Im ersteren erstellen wir eine abstrakte Klasse, die wir im weiteren Verlauf benötigen. In zaehler_bloc.dart programmieren wir den Mechanismus für den BloC.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'zaehler_ereignis.dart'; | |
class ZaehlerBloc { | |
int _zaehler = 0; | |
final _zaehlerStateController = StreamController<int>(); | |
StreamSink<int> get _inZaehler => _zaehlerStateController.sink; | |
Stream<int> get zaheler => _zaehlerStateController.stream; | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
final _zaehlerStateController = StreamController<int>(); | |
StreamSink<int> get _inZaehler => | |
_zaehlerStateController.sink; // die Variable ist privat | |
Stream<int> get zaheler => | |
_zaehlerStateController.stream; // die Variable ist öffentlich | |
final _zaehlerEventController = StreamController<ZaehlerEreignis>(); | |
Sink<ZaehlerEreignis> get zaehlerEventSink => _zaehlerEventController.sink; |
- mit dem StateController überwachen wir die Variable
- mit dem EventController verarbeiten wir die Ereignisse
Um die Ereignisse von dem EventController zu verarbeiten, müssen wir auf ihn "hören". Das wir im Konstruktor von ZaehlerBloc implementiert:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ZaehlerBloc() { | |
_zaehlerEventController.stream.listen(_mapEventToState); | |
} | |
void _mapEventToState(ZaehlerEreignis event) { | |
if (event is AdditionsEreignis) | |
_zaehler++; | |
else | |
_zaehler--; | |
_inZaehler.add(_zaehler); | |
} | |
void dispose() { | |
_zaehlerStateController.close(); | |
_zaehlerEventController.close(); | |
} |
Am Schluss schließen wir mit dispose noch die zwei Controller. Man beachte das im Konstruktor jetzt die Ereignisse verarbeitet werden.
Was ist noch zu tun ?
Jetzt muss noch der Code im main.dart File angepasst werden. Wir müssen einen StreamBuilder einbauen und den onPressed Code ändern. Wer den originalen Boilerplate Code anschaut, wird den Aufwand sicher für übertrieben halten. Schliesslich funktionieren beide Versionen. Wer sich aber vor Augen führt das bei einem grösseren Projekt einige, und vor allem, an verschiedene State's zu verarbeiten sind, wird das Konzept zu schätzen wissen. Wer mag..hier noch der komplette Code.
Kommentare
Kommentar veröffentlichen