Content
How can we pass information from one widget to another? That is what the BLoC (Business Logic Component) pattern is all about.
At the core of the BLoC pattern is the idea that every information in flutter should transit via streams of events. The streams should be regrouped somewhere, and can be accessible everywhere in the app.
So a BLoC file is a dart
file in our app, where we put our streams. We will be able to have sinks
and streams
in order to change some information, or to get it.
For instance, let’s take an app where we want to have access to some entries of anything, and we’ll call them InfoEntry
, and we have several of them, so we’ll make a list of them.
Create a bloc file called entries_bloc.dart
class EntriesBloc implements BlocBase {
@override
void dispose() {
// TODO here we'll close our streams
}
}
And the bloc_base.dart
file:
abstract class BlocBase {
void dispose();
}
In our EntriesBloc
class, we’ll initialize a few streams. First, an output stream, which is the one that will be used within our pages to display the entries.
Stream<List<InfoEntry>> infoEntries;
Then we want to add some broadcast controllers: they will receive events when we will want
Then we add some input streams in order to add, modify and delete infoEntries. We will be able to call them from our pages. For that, we want to create broadcast controllers, and access to them outside our class.
final _addEntryController = StreamController<InfoEntry>.broadcast();
final _modifyEntryController = StreamController<InfoEntry>.broadcast();
final _deleteEntryController = StreamController<InfoEntry>.broadcast();
// Here are the sinks we will access from our pages
StreamSink<InfoEntry> get inAddEntry => _addEntryController.sink;
StreamSink<InfoEntry> get inModifyEntry => _modifyEntryController.sink;
StreamSink<InfoEntry> get inDeleteEntry => _deleteEntryController.sink;
We have to link the controllers for modifying the list of entries to a method that handles the data.
EntriesBloc() {
// Listens for changes to the controller and
// calls the method to handle data on change
_addEntryController.stream.listen(_handleAddEntry);
_modifyEntryController.stream.listen(_handleModifyEntry);
_deleteEntryController.stream.listen(_handleDeleteEntry);
}
To link the infoEntries to real database data, we can use the Moor library, because it integrates really well with streams.
So we can add something like this in the constructor:
infoEntries = moorDatabase.watchInfoEntries();
The stream infoEntries is linked directly to the database stream, so we can use it in a StreamBuilder component.