BLoC-Muster mit einem einfachen Beispiel

Und noch einmal über BLoC anhand des klassischen Flutter Counter-Beispiels.


Als ich einige Artikel über reaktives Programmieren und die Verwendung des BLoC-Musters in Anwendungen las, stellte ich fest, dass ich etwas nicht nachholte. Wie üblich gibt es nicht genug Zeit für alles, aber jetzt gab es eine freie Stunde und es gibt Kraft - entschlossen schreibe ich die einfachste Flutter-Anwendung mit dem BLoC-Muster.


Unter Katze animashka Anwendungen und Erklärungen, warum ich es so geschrieben habe. Sehr interessant ist die Meinung der Community.


Bild


Ja, wir haben bereits viele Male über dieses Muster geschrieben, aber es gibt ohnehin keine klaren Anweisungen und Regeln für dessen Verwendung, und es stellt sich oft die Frage, wie die Logik in der Anwendung korrekt implementiert werden kann.


Ziel des Artikels ist es, mir und den Lesern ein wenig Klarheit zu verschaffen.


Also, die Definition des Musters, wie es von Google-Ingenieuren geäußert wurde - BLOC ist eine einfache Klasse, in der:


  1. alle ausgegebenen Streams
  2. Alle Eingaben sind Streams
  3. Diese Klasse sollte die Logik von der visuellen Schnittstelle entfernen

Um dieses Muster zu implementieren, können wir, falls erforderlich, die rxdart- Bibliothek verwenden, jedoch möglicherweise nicht.


Dies wird die Reaktivität nicht aufheben, wie Sie vielleicht denken. Während die Entwickler des Pakets selbst schreiben, fügt rxdart den bereits integrierten umfangreichen Funktionen der Dart-Sprache beim Arbeiten mit Streams Funktionen hinzu.


App



Daher nehmen wir die Anwendung mit Zählern, die beim Erstellen des Projekts automatisch erstellt werden, und versuchen, sie unter Verwendung des BLoC-Musters neu zu schreiben.


Aufgaben:


  1. Entfernen Sie alle Logik aus Widgets
  2. Empfangen Sie in der BLoC-Klasse nur Eingabestreams und geben Sie nur Ausgabestreams aus. Zum Beispiel die in den Kommentaren zum Artikel vorgeschlagene Funktion.

Bild


Es passt nicht zu uns, da es gegen die Regel verstößt, nur Streams an die Klasse weiterzuleiten.


Lösung:


  1. Wir entfernen die gesamte Logik aus den Widgets. Wir machen die Klasse Stateless und stoppen die Aktualisierung des Status mit setState.
  2. Wir zeigen die Zählerstände an verschiedenen Stellen mit dem eingebauten Widget an, das speziell für die Anzeige von Daten aus Streams entwickelt wurde - StreamBuilder.

class MyHomePage extends StatelessWidget { CounterBloc counterBloc = CounterBloc(); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: StreamBuilder<int>( stream: counterBloc.pressedCount, builder: (context, snapshot) { return Text( 'Flutter Counter Bloc Example - ${snapshot.data.toString()}', ); }), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Text( 'You have pushed the button this many times:', ), StreamBuilder<int>( stream: counterBloc.pressedCount, builder: (context, snapshot) { return Text( '${snapshot.data.toString()}', style: Theme.of(context).textTheme.display1, ); }), ], ), ), floatingActionButton: Container( width: 100.0, height: 100.0, child: FloatingActionButton( onPressed: () { counterBloc.incrementCounter.add(null); }, tooltip: 'Increment', child: Text( "+ \n send \n to BLoC", textAlign: TextAlign.center, ), ), ), ); } } 

  1. Wir erstellen eine separate Klasse, in der wir das BLoC-Muster implementieren:
    3.1 Alle Klasseneigenschaften und Methoden sind ausgeblendet.
    3.2 Um den Status zu empfangen und zu übertragen, verwenden wir Streams, die von außen mit Gettern sichtbar sind (aber hier ist ein cooler Artikel darüber ).

 class CounterBloc { int _counter; CounterBloc() { _counter = 1; _actionController.stream.listen(_increaseStream); } final _counterStream = BehaviorSubject<int>.seeded(1); Stream get pressedCount => _counterStream.stream; Sink get _addValue => _counterStream.sink; StreamController _actionController = StreamController(); StreamSink get incrementCounter => _actionController.sink; void _increaseStream(data) { _counter += 1; _addValue.add(_counter); } void dispose() { _counterStream.close(); _actionController.close(); } } 

Das ist alles, wir haben ein funktionierendes Beispiel, in dem wir Datenströme senden und empfangen und Daten in den erforderlichen Widgets anzeigen, ohne dass im visuellen Teil eine Logik angewendet wird.


So können wir alle Berechnungen, Datenübertragungen usw. trennen. von der Schnittstelle. Wenn Sie zum Beispiel abhängig von der Menge unterschiedliche Etiketten zum Zähler hinzufügen und diese aus einer externen Datenbank entnehmen, durchläuft die gesamte Logik bereits BLoC - unsere Benutzeroberfläche weiß nichts darüber.


Hinweis 1: Beachten Sie, dass wir eine Instanz der Klasse erstellen.> CounterBloc counterBloc = CounterBloc (); und dann bekommen wir Daten daraus. Wenn wir diese Daten auf verschiedenen Bildschirmen (in getrennten Klassen) benötigen, können wir entweder geerbte Widgets für die Übertragung verwenden oder Singleton aus unserer Klasse machen.


Github Beispielcode


Gute Kodierung an alle!


Fortsetzung


In der Folge übertragen wir den Status auf verschiedene Bildschirme, speichern die Daten im permanenten Speicher des Telefons und testen BLoC https://habr.com/de/post/485002/

Source: https://habr.com/ru/post/de475404/


All Articles