Flutter Library: flutter_bloc
![]() |
London |
Sie soll im Vergleich die Handhabung von BloC vereinfachen. Zum testen setzen wir dabei das Counter Beispiel, das per Voreinstellung bei jedem neuen Flutter Projekt in Visual Studio generiert wird, als BloC Variante um. Das klingt an sich langweilig, aber es geht ja mehr um die Handhabung von BloC, als um das Ergebnis der App.
Flutter BloC Pattern
Das BloC File
Fangen wir mit dem interessantesten Teil an , der BloC Implementation:
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 'package:bloc/bloc.dart'; | |
enum ZaehlerEreignis { Addieren, Subtrahieren} | |
class ZaehlerBloc extends Bloc<ZaehlerEreignis,int>{ | |
int get initialState => 0; | |
@override | |
Stream<int> mapEventToState(ZaehlerEreignis ereignis) async*{ | |
switch (ereignis) { | |
case ZaehlerEreignis.Subtrahieren: | |
yield currentState -1; | |
break; | |
case ZaehlerEreignis.Addieren: | |
yield currentState +1; | |
break; | |
} | |
} | |
} |
Mit ZaehlerBloc erweitern wir die Klasse Bloc, eine abstrakte Klasse:
Bloc<Event,State>
In unserem Beispiel nimmt Bloc<ZaehlerEreignis,int>, also mit ZaehlerEreignis, was entweder Addieren oder Subtrahieren ist, und mit int für den State, zwei "einfache" Werte auf. Ein Event ist ein Ereignis, welches unser BloC verarbeiten soll. Der State wiederum ist der Output, die Ausgabe, unseres BLoC's. Ereignisse werden also verarbeitet und generieren eine Ausgabe, auf die Teile unserer UI hören können, um gegebenenfalls einen Neuaufbau auszulösen. Man spricht in diesem Zusammenhang auch von einem Stream der bearbeitet wird, da man die eintreffenden / ausgehenden Daten, auch als Strom von Daten verstehen kann.
int get initialState => 0;
Mit initialState definieren wir den Startzustand des State's, also 0. Diese Initialisierung ist Pflicht und kann nicht ausgelassen werden. Das gleiche gilt für Stream<int> mapEventToState . Diese Methode / Funktion nimmt ein eintreffendes Ereignis, in unserem Beispiel ein ZaehlerEreignis, und wandelt es in einen neuen State um. Diese Funktion wird immer aufgerufen, wenn ein neues Ereignis im BloC eintrifft und retourniert einen int Wert.
Der Code Teil in der Switch Sektion ist die eigentliche Umwandlung des Ereignisses in einen neuen State. Hier muss man erwähnen, das der Funktionskörper mit dem Schlüsselwort async* bezeichnet ist. Als nächstes schauen wir uns kurz main.dart an:
Das main.dart File
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 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:tut_20/zaehler_bloc.dart'; | |
import 'package:tut_20/zaehler_seite.dart'; | |
void main() => runApp(MyApp()); | |
class MyApp extends StatefulWidget { | |
@override | |
State<StatefulWidget> createState() => MyAppState(); | |
} | |
class MyAppState extends State<MyApp> { | |
final ZaehlerBloc _counterBloc = ZaehlerBloc(); | |
@override | |
Widget build(BuildContext context) { | |
return MaterialApp( | |
title: 'Flutter Demo', | |
home: BlocProvider<ZaehlerBloc>( | |
bloc: _counterBloc, | |
child: ZaehlerSeite(), | |
), | |
); | |
} | |
@override | |
void dispose() { | |
_counterBloc.dispose(); | |
super.dispose(); | |
} | |
} |
BlocProvider<ZaehlerBloc>
implementieren wir ein Flutter Widget, das seinen Kindern in der Hierarchie, einen Bloc zur Verfügung stellt, also den Zugriff darauf. Den Zugriff ermöglicht haben wir im Vorfeld durch
final ZaehlerBloc _counterBloc = ZaehlerBloc();
Diese Zeile schafft ein Objekt vom Typ ZaehlerBloc und generiert damit die Variable _counterBloc.
Sie wird auch dem BlocProvider im Feld bloc: übergeben. Mit child:, unserem Kind das durch den BlocProvider auch Zugriff auf unseren BloC hat, implementieren wir die eigentliche UI. Zu guter Letzt der Teil mit dem Code für dispose. Er sorgt dafür das die Ressourcen anschließend wieder ordnungsgemäß freigegeben werden und ist auch Pflicht.
Das zaehler_seite.dart File
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 'package:flutter/material.dart'; | |
import 'package:flutter_bloc/flutter_bloc.dart'; | |
import 'package:tut_20/zaehler_bloc.dart'; | |
class ZaehlerSeite extends StatelessWidget { | |
@override | |
Widget build(BuildContext context) { | |
final ZaehlerBloc _counterBloc = BlocProvider.of<ZaehlerBloc>(context); | |
return Scaffold( | |
appBar: AppBar(title: Text('Zaehler')), | |
body: BlocBuilder<ZaehlerEreignis, int>( | |
bloc: _counterBloc, | |
builder: (BuildContext context, int count) { | |
return Center( | |
child: Text( | |
'$count', | |
style: TextStyle(fontSize: 24.0), | |
), | |
); | |
}, | |
), | |
floatingActionButton: Column( | |
crossAxisAlignment: CrossAxisAlignment.end, | |
mainAxisAlignment: MainAxisAlignment.end, | |
children: <Widget>[ | |
Padding( | |
padding: EdgeInsets.symmetric(vertical: 5.0), | |
child: FloatingActionButton( | |
child: Icon(Icons.add), | |
onPressed: () { | |
_counterBloc.dispatch(ZaehlerEreignis.Addieren); | |
}, | |
), | |
), | |
Padding( | |
padding: EdgeInsets.symmetric(vertical: 5.0), | |
child: FloatingActionButton( | |
child: Icon(Icons.remove), | |
onPressed: () { | |
_counterBloc.dispatch(ZaehlerEreignis.Subtrahieren); | |
}, | |
), | |
), | |
], | |
), | |
); | |
} |
BlocProvider.of<ZaehlerBloc>(context);
Anschließend wird im body: Eintrag das BlocBuilder Widget verwendet. Er nimmt als Einträge einen Bloc, in diesem Fall _counterBloc, und einen Builder. Was bleibt ist noch die Implementation bei den Buttons. Da wir ja Zugriff auf den _counterBloc haben, benutzen wir dessen Methode dispatch, um ein neues Event auszulösen, welches in unserem Bloc verarbeitet wird. Entweder addieren oder subtrahieren.
Für mich als Amateur hat es ein wenig gedauert bis ich Begriffen habe, wie das ganze funktioniert. Vor allem, wie kommt $count zu seinem Wert ?
Original Quellen: Homepage zu der bloc Library. Autor Felix Angelov. Mehr von diesem Autor gibt es hier.
Kommentare
Kommentar veröffentlichen