I am trying to use bloc architecture in Flutter app and for this purpose I use StreamController and StreamBuilder. The issue is, that StreamBuilder repeats the last snapshot.data every time it's returned. I am nesting StreamBuilders. So there is one main StreamBuilder. Its stream is defined in a mainBloc file. InitialData is SomeEvent and someView is returned.
SomeView is another StreamBuilder with its corresponding bloc and stream. The initialData is InitialEvent. On pressing a button SecondEvent is added to the bloc sink and therefore the widget changes. In the new view there is another button and on tapping it the mainBloc should show the same SomeView again.
The issue is here. The SomeView StreamBuilder receives snapshot.data that is the same as the last one, but the last one is not added to the sink again. So I don't get - is this how StreamBuilder is supposed to work? What I'd like to achieve is that snapshot.data has the InitialEvent instead. Is this possible? Or at least to not have the snapshot.data repeated without triggering.
The code below demonstrates the whole issue.
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
MainBloc mainBloc;
Bloc bloc;
MyApp() {
mainBloc = MainBloc();
bloc = Bloc();
}
Widget mainView() {
return StreamBuilder<MainEvent>(
stream: mainBloc.mainStream,
initialData: SomeEvent(),
builder: (
context,
snapshot,
) {
if (snapshot.hasData) {
MainEvent event = snapshot.data;
if (event is SomeEvent) {
return someView();
}
if (event is SomeEventTwo) {
return someView();
}
} else {
return Container(height: 0, width: 0);
}
},
);
}
Widget someView() {
return StreamBuilder<Event>(
stream: bloc.stream,
initialData: InitialEvent(),
builder: (
context,
snapshot,
) {
if (snapshot.hasData) {
Event event = snapshot.data;
if (event is InitialEvent) {
return Column(
children: [
Center(
child: Text("Initial event"),
),
FlatButton(
onPressed: () {
bloc.secondEvent();
},
child: Text("Trigger Second event"),
color: Colors.pink,
),
],
);
}
if (event is SecondEvent) {
return Center(
child: FlatButton(
child: Text("Show same screen again"),
onPressed: () {
bloc.dispose();
bloc = Bloc();
mainBloc.showScreenTwo();
},
color: Colors.blue,
),
);
}
} else {
return Container(height: 0, width: 0);
}
},
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
backgroundColor: Colors.grey,
),
body: mainView(),
),
);
}
}
These are the blocs: MainBloc:
class MainBloc {
StreamController<MainEvent> _mainStreamController;
StreamSink<MainEvent> get _mainSink => _mainStreamController.sink;
Stream<MainEvent> get mainStream => _mainStreamController.stream;
MainBloc() {
_mainStreamController = StreamController<MainEvent>();
}
void showScreen() {
_mainSink.add(SomeEvent());
}
void showScreenTwo() {
_mainSink.add(SomeEventTwo());
}
}
abstract class MainEvent {}
class SomeEvent extends MainEvent {}
class SomeEventTwo extends MainEvent {}
Bloc:
class Bloc {
StreamController<Event> _controller;
StreamSink<Event> get _sink => _controller.sink;
Stream<Event> get stream => _controller.stream;
Bloc() {
_controller = StreamController<Event>();
}
void secondEvent() async {
_sink.add(SecondEvent());
}
dispose() {
_controller.close();
}
}
abstract class Event {}
class InitialEvent extends Event {}
class SecondEvent extends Event {}