Reputation: 375
bloc.dart
class Bloc{
Bloc(){
additionalController.stream.listen(onAdd);
}
void dispose() async {
additionalController.close();
_itemAdd.close();
}
final additionalController = StreamController<Data>();
Sink<Data> get addItem => additionalController.sink;
Stream<String> get addGet => _itemAdd.stream;
final _itemAdd = BehaviorSubject<String>();
void onAdd(Data data) {
_addWork(data);
}
Future<Null> _addWork(Data data) async {
//work
}).whenComplete(() {
_itemAdd.add("complete work");
}).catchError((e) {
_itemAdd.addError("Error in Adding Data");
});
}
}
As bloc
should only be used and shared to handle the business logic, but the error handling part has nothing to do with the business logic.
How to show callbacks and error of bloc on UI. I don't think StreamBuilder
is the only solution.
If we use StreamBuilder
, In that way, We repetitively send callback to bloc every time rebuilding happens and this make no sense.
Is there a right way to do this?
Thank you in advance!!
Upvotes: 1
Views: 4045
Reputation: 79
According to the Dart docs this can be done in Dart 2.1 with mixin:
Version note: Support for the mixin keyword was introduced in Dart 2.1. Code in earlier releases usually used abstract class instead. For more information on 2.1 mixin changes, see the Dart SDK changelog and 2.1 mixin specification.
Example:
mixin Music {
void play();
}
class Musician {
Music _delegate;
Musician(Music delegate){
_delegate = delegate;
}
play(){
_delegate.play();
}
}
class MyMusicWidget extends StatelessWidget with Music{
@override
Widget build(BuildContext context) {
return Container(
child: Text("Music")
);
}
@override
void play() {
// TODO: implement play
// Your code here!
}
}
Upvotes: 1
Reputation: 136
What has worked for me so far, is using an interface that represents a callback.
abstract class AddItemDelegate {
void onSuccess();
void onError(String message);
}
Then using it in the bloc
as follows:
class Bloc {
AddItemDelegate _delegate;
// ...
Function addItem(Data item, AddItemDelegate delegate) => () {
_delegate = delegate;
additionalController.sink.add(item);
}
// ...
Future<Null> _addWork(Data data) async {
try {
final work = await //work...
_itemAdd.add("complete work");
_delegate?.onSuccess();
}
catch(e) {
final error = "Error in Adding Data";
_itemAdd.addError(error);
_delegate?.onError(error);
}
}
}
Then on your StatefulWidget
(orStatelessWidget
) you can do the following:
class MyWidget extends StatelessWidget implements AddItemDelegate {
@override
void onSuccess() {
// e.g.: Show a dialog or navigate to other screen
}
@override
void onError(String message) {
// e.g.: Show an error dialog
}
@override
Widget build(BuildContext context) {
final bloc = // ...
final data = // ...
return MaterialButton(
child: Text("Add Item"),
onPressed: bloc.addItem(data, this));
}
}
This way one can use callbacks while using BLoC pattern.
Upvotes: 12