I have recently heard and read a lot about the BLoC architecture and it makes a lot of sense and is similar to program structures I have used before.
However, one thing I have found unclear is the streams that a BLoC should instantiate and make available.
Let us consider that the app user has two buttons, which when pressed will create two distinct objects which need to be handled by distinct methods in the BLoC. I am unsure whether this warrants the creation of two StreamController
objects and exposing two sinks, or if they should share a common StreamController
and the actions are differentiated between using runtime type checking.
The two approaches are as follows; the first approach creates two stream controllers in the BLoC:
final _actionOneController = StreamController<ActionOne>();
StreamSink<ActionOne> get actionOne => _actionOneController.sink;
final _actionTwoController = StreamController<ActionTwo>();
StreamSink<ActionTwo> get actionTwo => _actionTwoController.sink;
creates two events by adding them to different sinks:
Button(child: Text("Action One"), onPressed: () => bloc.actionOne.add(ActionOne(data, data1, data3)),
Button(child: Text("Action Two"), onPressed: () => bloc.actionTwo.add(ActionTwo(someOtherData)),
and handles them by listening to two streams separately.
The second approach exposes a single StreamSink
:
final _actionController = StreamController<Action>();
StreamSink<Action> get action => _actionController.sink;
create the two events by adding them to the common sink:
Button(child: Text("Action One"), onPressed: () => bloc.action.add(ActionOne(data, data1, data3)),
Button(child: Text("Action Two"), onPressed: () => bloc.action.add(ActionTwo(someOtherData)),
and then differentiate between the actions in the BLoC with a method that checks the runtime type of the Action
object:
void _actionListener(Action action){
if(action is ActionOne)
actionOneHandler(action);
if(action is ActionTwo)
actionTwoHandler(action);
}
I would like to emphasize that the two actions create distinct objects with no common fields i.e. they do not share a commonly inherited ancestor class.