Call two event at the same time in initState - flutter

How to call two different events at the same time inside initState because these two events calling different api's. Whenever i put two events inside initState only one event is triggers. I seen some articles that it is not possible to call rather than creating two different bloc's. Any possibilities to calling two events at the same time.
late HomeBloc homeBloc;
#override
void initState() {
homeBloc = BlocProvider.of<HomeBloc>(context);
homeBloc.add(LoadRestaurantCuisineDishes());
homeBloc.add(LoadRestaurantRecommendedForYouEvent());
super.initState();
}

You can use transformEvents method of bloc with rxDart like mentioned in issue here
First, you should import rxDart and then add transformEvents function to your bloc like:
#override
Stream<Transition< BookEvent, BooksState >> transformEvents(
Stream< BookEvent > events,
TransitionFunction< BookEvent, BooksState > transitionFn,
) {
return events.flatMap(transitionFn);
}

Related

Flutter: In which order should super() be called with dispose() and initState()? (example with a focusNode) [duplicate]

I am confused as to where to call the super.initSate() in Flutter? In some code examples, it's called at the beginning and in others at the end. Is there a difference?
I have tried to google this but haven't found any explanation on the position of this function call.
Which one is correct?
void initState() {
super.initState();
//DO OTHER STUFF
}
or
void initState() {
//DO OTHER STUFF
super.initState();
}
It does matter for mixins (and because of that for you as well)
It is a paradigm in the Flutter framework to call the super method when overriding lifecycle methods in a State. This is why even deactivate has a mustCallSuper annotation.
Additionally, some mixins expect that you call the super methods of those lifecycle methods at a particular point in the function.
This means that you should follow the documentation and call super.dispose at the end of your dispose method because mixins on State in the framework expect that this is the case.
For example: TickerProviderStateMixin and SingleTickerProviderStateMixin assert super.dispose at the end:
All Tickers must [..] be disposed before calling super.dispose().
Another example: AutomaticKeepAliveMixin executes logic in initState and dispose.
Conclusion
Start your initState with super.initState and end your dispose with super.dispose if you want to be on the easy and safe side adding mixins to your State.
Furthermore, follow the documentation for other lifecycle methods (any method you overwrite in State) because the framework will expect that you call the super methods as described in the documentation.
Thus, the following is what you should do:
#override
void initState() {
super.initState();
// DO YOUR STUFF
}
#override
void dispose() {
// DO YOUR STUFF
super.dispose();
}
However, it does not really matter for State, which I will explain in the following and even for mixins, it only matters for assertions judging from what I could find - so it would not affect your production app.
It does not matter for State
I think that the previous two answers from Pablo Barrera and CopsOnRoad are misleading because the truth of the matter is that it really does not matter and you do not need to look far.
The only actions that super.initState and super.dispose take in the State class itself are assertions and since assert-statements are only evaluated in debug mode, it does not matter at all once build your app, i.e. in production mode.
In the following, I will guide you through what super.initState and super.dispose do in State, which is all the code that will be executed when you have no additional mixins.
initState
Let us look exactly what code is executed in super.initState first (source):
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
As you can see, there is only a lifecycle assertion and the purpose of it is to ensure that your widget works correctly. So as long as you call super.initState somewhere in your own initState, you will see an AssertionError if your widget is not working as intended. It does not matter if you took some prior action because the assert is only meant to report that something in your code is wrong anyway and you will see that even if you call super.initState at the very end of your method.
dispose
The dispose method is analogous (source):
#protected
#mustCallSuper
void dispose() {
assert(_debugLifecycleState == _StateLifecycle.ready);
assert(() {
_debugLifecycleState = _StateLifecycle.defunct;
return true;
}());
}
As you can see, it also only contains assertions that handle debug lifecycle checking. The second assert here is a nice trick because it ensures that the _debugLifecycleState is only changed in debug mode (as assert-statements are only executed in debug mode).
This means that as long as you call super.dispose somewhere in your own method, you will not lose any value without mixins adding additional functionality.
super.initState() should always be the first line in your initState method.
From docs:
initState(): If you override this, make sure your method starts with a call to
super.initState().
As you could see in the classes from the framework, you should do everything after the widget is initialized, meaning after super.initState().
I case of dispose would be logically in the other way, first do everything and then call super.dispose().
#override
void initState() {
super.initState();
// DO STUFF
}
#override
void dispose() {
// DO STUFF
super.dispose();
}
initState called up by default whenever a new stateful widget is added into a widget tree.
Now the super.initState performs the default implementation of the base class of your widget.If you call anything before super.initState that depends on the base class then this might cause problem.
That's why it's recommended that you call initState in this fashion:
#override
void initState() {
super.initState();
// DO STUFF
}

Does autoDispose in riverpod works same as dispose lifecycle in Flutter?

Does autoDispose in Riverpod's StateProvider disposes controllers?
Does both the following statements works similarly?
final _controller = StateProvider.autoDispose((ref) => PageController());
or
final _controller = PageController();
#override
void dispose() {
_controller.dispose();
super.dispose();
}
autoDispose modifier, as the name suggests, disposes call of the resources when the provider is not used, it simply frees up memory without us specifying any dispose function.
One example that may help you for example when you navigate into another page in which you have a provider with autoDispose, if you go back to your first page your provider data will reset, without autoDispose, everything will be saved.

using didUpdateWidget to replace a stream causes "bad state: Stream has already been listened to"

I have a StreamBuilder that I want to be able to pause and unpause and, since StreamBuilder doesn't expose it's underlying StreamSubscription, I have to create a proxy stream to forward the source stream's elements while exposing a StreamSubscription that I can pause and unpause. This forces me to convert my stateless widget into a stateful widget so I have access to dispose and can close it's StreamController.
I'm following the didUpdateWidget documentation's instructions:
In initState, subscribe to the object.
In didUpdateWidget unsubscribe from the old object and subscribe to the new one if the updated widget configuration requires replacing the object.
In dispose, unsubscribe from the object.
I need to replace the Stream whenever the user types in a new search query. My stateful widget is re-constructed within a ChangeNotifier whenever a new stream is received.
Here's the relevant part of my stateful widget:
final Stream<List<Entry>> _entryStream;
StreamController<List<Entry>> _entryStreamController;
StreamSubscription<List<Entry>> _entryStreamSubscription;
_EntryListState(this._entryStream);
void initStream() {
_entryStreamController?.close();
_entryStreamController = StreamController();
_entryStreamSubscription = _entryStream.listen((event) {
_entryStreamController.add(event);
}
)..onDone(() => _entryStreamController.close());
}
#override
void initState() {
initStream();
super.initState();
}
#override
void dispose() {
_entryStreamController?.close();
super.dispose();
}
#override
void didUpdateWidget(EntryList oldEntryList) {
// Initialize the stream only if it has changed
if (oldEntryList._entryStream != _entryStream) initStream();
super.didUpdateWidget(oldEntryList);
}
This is the line throwing the BadState error:
_entryStreamSubscription = _entryStream.listen((event) {
_entryStreamController.add(event);
}
And here is where my widget is being constructed:
child: Consumer<SearchStringModel>(
builder: (context, searchStringModel, child) {
print('rebuilding with: ${searchStringModel.searchString}');
var entryStream = _getEntries(searchStringModel.searchString);
return EntryList(entryStream);
}
),
I don't think I understand didUpdateWidget in particular and suspect that's where the two issues (bad state, and not updating) are coming from? I'm also re-constructed the stateful widget instead of just modifying its state which is a little confusing, but the widget is intended to act as a stateless widget for all intents and purposes so it'd be a pain to update it to update state instead of reconstructing. Any advice?
I had not read the "didUpdateWidget" documentation closely enough. This is the key paragraph:
/// If the parent widget rebuilds and request that this location in the tree
/// update to display a new widget with the same [runtimeType] and
/// [Widget.key], the framework will update the [widget] property of this
/// [State] object to refer to the new widget and then call this method
/// with the previous widget as an argument.
In my consumer, I'm rebuilding with a new EntryList. As the above paragraph describes, the framework will then call didUpdateWidget on the same state object (as opposed to a new one). In order to check whether or not the configuration has changed and, if it has, to access the new configuration, I need to access the widget property of my state object. With this in mind, here is my new implementation of didUpdateWidget:
#override
void didUpdateWidget(EntryList oldEntryList) {
super.didUpdateWidget(oldEntryList);
// Initialize the stream only if it has changed
if (widget._entryStream != _entryStream) {
_entryStream = widget._entryStream;
initStream();
}
}
Note that I am now checking widet._entryStream and then setting the state's _entryStream to it if it's changed.
Hopefully someone else running into a similar problem will be helped by this!

Best practice to use mapEventToState with incoming streams?

Is there any elegant way to map incoming streams from a private api directly inside mapEventToState() without having to create redundant private events in the bloc?
I came with this solution. It's ok with one single stream, but with multiple streams it starts to get a mess. Thanks in advance.
// (don't mind the imports, this is the bloc file)
class ExampleBloc extends Bloc<ExampleEvent, ExampleState> {
final MyPrivateApi api = MyPrivateApi.instance; // singleton
ExampleBloc() {
// api has a stream of booleans
api.myStream.listen((b) {
// if it's true fire this event
if (b) this.add(_MyPrivateEvent());
}
#override
ExampleState get initialState => InitialExampleState();
#override
Stream<ExampleState> mapEventToState(
ExampleEvent event,
) async* {
if (event is _MyPrivateEvent) {
yield SomeState;
}
}
// private Event
class _MyPrivateEvent extends ExampleEvent {
}
As I can see, you can subscribe on event updates in your screen, and push event from screen to Bloc if need some calculations. Code will be more clean.
Your way seems to be the only way works and seems to be used - see this bloc issue: https://github.com/felangel/bloc/issues/112 and this example project: https://github.com/algirdasmac/streams_and_blocs
Just make sure to dispose the subscription that gets returned by api.myStream.listen.
Previous answer
The following DOES NOT work for infinite streams because the generator function will await until the stream finishes. This can only be used for stream the complete fast, like maybe an upload/download progress.
See accepted answers here Dart yield stream events from another stream listener and here Dart/Flutter - "yield" inside a callback function
ExampleBloc() {
_MyInitEvent();
}
#override
Stream<ExampleState> mapEventToState(
ExampleEvent event,
) async* {
if (event is _MyInitEvent) {
await for (bool b in api.myStream) {
if (b) yield SomeState;
}
}
}
Build another block that encapsulate your stream of bytes.
You can make two events (ByteRead and ByteConsume) and two states (ByteWaiting and ByteAvailable).
Byteread and ByteAvailable should have a _byte field for storing data. Your bytebloc has a subscriber listening the stream and every time it reads a byte it fires a ByteRead event.
You should also add to the bloc a consume() method that gives the last byte readed and fires the ByteConsume event.
The two states and events are mutual:
you start in bytewaiting and every time you have a ByteRead you change to ByteAvailable and
every time you have a ByteConsume you change back to ByteWaiting.

Should I call super.initState at the end or at the beginning?

I am confused as to where to call the super.initSate() in Flutter? In some code examples, it's called at the beginning and in others at the end. Is there a difference?
I have tried to google this but haven't found any explanation on the position of this function call.
Which one is correct?
void initState() {
super.initState();
//DO OTHER STUFF
}
or
void initState() {
//DO OTHER STUFF
super.initState();
}
It does matter for mixins (and because of that for you as well)
It is a paradigm in the Flutter framework to call the super method when overriding lifecycle methods in a State. This is why even deactivate has a mustCallSuper annotation.
Additionally, some mixins expect that you call the super methods of those lifecycle methods at a particular point in the function.
This means that you should follow the documentation and call super.dispose at the end of your dispose method because mixins on State in the framework expect that this is the case.
For example: TickerProviderStateMixin and SingleTickerProviderStateMixin assert super.dispose at the end:
All Tickers must [..] be disposed before calling super.dispose().
Another example: AutomaticKeepAliveMixin executes logic in initState and dispose.
Conclusion
Start your initState with super.initState and end your dispose with super.dispose if you want to be on the easy and safe side adding mixins to your State.
Furthermore, follow the documentation for other lifecycle methods (any method you overwrite in State) because the framework will expect that you call the super methods as described in the documentation.
Thus, the following is what you should do:
#override
void initState() {
super.initState();
// DO YOUR STUFF
}
#override
void dispose() {
// DO YOUR STUFF
super.dispose();
}
However, it does not really matter for State, which I will explain in the following and even for mixins, it only matters for assertions judging from what I could find - so it would not affect your production app.
It does not matter for State
I think that the previous two answers from Pablo Barrera and CopsOnRoad are misleading because the truth of the matter is that it really does not matter and you do not need to look far.
The only actions that super.initState and super.dispose take in the State class itself are assertions and since assert-statements are only evaluated in debug mode, it does not matter at all once build your app, i.e. in production mode.
In the following, I will guide you through what super.initState and super.dispose do in State, which is all the code that will be executed when you have no additional mixins.
initState
Let us look exactly what code is executed in super.initState first (source):
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
As you can see, there is only a lifecycle assertion and the purpose of it is to ensure that your widget works correctly. So as long as you call super.initState somewhere in your own initState, you will see an AssertionError if your widget is not working as intended. It does not matter if you took some prior action because the assert is only meant to report that something in your code is wrong anyway and you will see that even if you call super.initState at the very end of your method.
dispose
The dispose method is analogous (source):
#protected
#mustCallSuper
void dispose() {
assert(_debugLifecycleState == _StateLifecycle.ready);
assert(() {
_debugLifecycleState = _StateLifecycle.defunct;
return true;
}());
}
As you can see, it also only contains assertions that handle debug lifecycle checking. The second assert here is a nice trick because it ensures that the _debugLifecycleState is only changed in debug mode (as assert-statements are only executed in debug mode).
This means that as long as you call super.dispose somewhere in your own method, you will not lose any value without mixins adding additional functionality.
super.initState() should always be the first line in your initState method.
From docs:
initState(): If you override this, make sure your method starts with a call to
super.initState().
As you could see in the classes from the framework, you should do everything after the widget is initialized, meaning after super.initState().
I case of dispose would be logically in the other way, first do everything and then call super.dispose().
#override
void initState() {
super.initState();
// DO STUFF
}
#override
void dispose() {
// DO STUFF
super.dispose();
}
initState called up by default whenever a new stateful widget is added into a widget tree.
Now the super.initState performs the default implementation of the base class of your widget.If you call anything before super.initState that depends on the base class then this might cause problem.
That's why it's recommended that you call initState in this fashion:
#override
void initState() {
super.initState();
// DO STUFF
}