If I instantiate a BLoC in MyWidget, I'll usually use a StatefulWidget and close the stream in the dispose method like so:
class _MyWidgetState extends State<MyWidget> {
...
#override
void initState() {
// ...
bloc = MyBloc()
}
#override
void dispose() {
bloc.stream.close();
// ...
}
...
}
However, when I inject a provided instance of MyBloc into MyWidget (maybe via MyWidget's constructor), I close the stream higher up the widget hierarchy since MyWidget does not get a new instance of MyBloc with a new Stream when the user navigates away from and back to MyWidget.
class MyWidget extends StatefulWidget {
final MyBloc bloc;
MyWidget(this.bloc) ... ;
..
}
class _MyWidgetState extends State<MyWidget> {
...
#override
void dispose() {
// Not closing stream here anymore. Closing higher up because
// I don't get a fresh instance when user comes back here;
// ...
}
}
Does this cause a memory leak?
That's not a problem, as long that the widget that created your object correctly dispose it when removed from the widget tree.
In fact, descendants should not call dispose on their parameters.
Doing so is an anti-pattern, as a descendant don't have the ownership of their parameter and therefore should not do any modifications on it.
Related
I have this stateful widget which uses a bloc called RecorderBloc:
class _RecorderScreenWidgetState extends State<RecorderScreenWidget> {
late final RecorderBloc _recorderBloc;
#override
void initState() {
super.initState();
_recorderBloc = serviceLocator.get<RecorderBloc>();
}
#override
void dispose() {
_recorderBloc.add(RecorderEvent.dispose());
super.dispose();
}
#override
Widget build(BuildContext context) {
//.....ommitted code
}
As you can see I need to dispose some members of the bloc after I finish from them, and that is done by adding a dispose event.
But I don't know if defining the bloc as a member variable of the stateful widget is the right approach?
If not, then how can I get the instance of the bloc inside the dispose() method of the StatefulWidget to add a dispose event?
As far as I know there is no need for defining a dispose event. The Bloc class has a close function which will be called when the provider widget (BlocProvider) state is being disposed. You can override that function inside of your BLoC and do whatever is needed.
class MyBloc extends Bloc<MyBlocState> {
#override
Future<void> close() {
// dispose
return super.close();
}
}
I have 2 custom widgets, and I want to use the same Bloc file.
My Bloc file gets data from the internet in the constructor.
class MyBloc {
// StreamControllers, StreamSinks, Streams ...
MyBloc() {
getDataFromInternet();
}
}
class MyWidget1 extends StatefulWidget {
MyWidget1({Key key}) : super(key: key);
#override
_MyWidget1State createState() => _MyWidget1State();
}
class _MyWidget1State extends State<MyWidget1> {
MyBloc _bloc;
#override
void initState() {
_bloc = MyBloc();
super.initState();
}
}
class MyWidget2 extends StatefulWidget {
MyWidget2({Key key}) : super(key: key);
#override
_MyWidget2State createState() => _MyWidget2State();
}
class _MyWidget2State extends State<MyWidget2> {
MyBloc _bloc;
#override
void initState() {
_bloc = MyBloc();
super.initState();
}
}
My problem is, that it downloads the data every time the screen changes (any of the two widgets appear on the screen).
Should I pass the initialized bloc object to the widgets in the constructors, and not create a new Bloc in the widgets constructor? I don't want to save the data and write logic to check if I already downloaded it or not.
Use this bloc implementation https://bloclibrary.dev/
Your bloc will have single instance with it's single state at the moment. Invoke new state depending on previous and you will never has problems with unneeded queries or something like this.
I have StatefulWidget instance.
However I want to access the method of State from the instance of StatefulWidget.
It might be very simple and basic for flutter, but for the beginner of Stateful/State systen, it is a bit complex.
class MainBody extends StatefulWidget{
#override
_MainBodyState createState() => _MainBodyState();
}
class _MainBodyState extends State<MainBody>{
_MainBodyState();
void connectMainBody(){
print("ConnectMainBody");
}
class _MyHomePageState extends State<MyHomePage> {
Widget mainBody;
#override
void initState() {
super.initState();
mainBody = new MainBody();
mainBody.connectMainBody()// how can I access this method??
}
My idea was completely wrong.
https://medium.com/flutter-community/flutter-communication-between-widgets-f5590230df1e
I checked this page and learned.
How to access from Parent to Child.
By giving parameters to Child's Constructor.
How to access from Child to Parent.
By using callback function given to Child from Parent in advance.
I think I should learn about GlobalKey next.
Thank you very much for your advice.
I'm currently learning Flutter. I tried to deep dive into Flutter Widget life-cycle, and I wonder why StatefulWidget are written like this :
class Example extends StatefulWidget {
#override
_ExampleState createState() => _ExampleState();
}
class _ExampleState extends State<Example> {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
but not :
class Example extends StatefulWidget {
// initState
// setState
// ...
#override
Widget build(BuildContext build) {
...
}
}
I think the latter makes the source simple. But I don't know why they're using the former style ?
The reason why StatefulWidget uses a separate State class and not having build method inside its body is because all fields inside a Widget are immutable, and this includes all its sub-classes.
You might have noticed that StatelessWidget has its build and other associated methods defined inside it, but that was possible due to the nature of StatelessWidget which is rendered completely using the provided info, and doesn't expect any future change in its State.
In the case of StatefulWidget, State information occasionally change (or expected to change) during the course of the app, thus this information isn't suitable for storage in a final field (build) to satisfy Widget class conditions (all fields are immutable). That's why State class is introduced. You just have to override the createState function to attach your defined State to your StatefulWidget, and let all that change happens in a separate class.
I keep primitive states inside State. But for objects, the following works:
class _Like extends StatefulWidget {
final Post _post; <-- mutable object is here
_Like(this._post);
#override
State<StatefulWidget> createState() => _LikeState();
}
class _LikeState extends State<_Like> {
...
_like() {
setState(() {
widget._post.liked = !widget._post.liked; <-- mutated here
});
}
...
}
What would the be reason not to use this approach? (As opposed to moving the state inside State, preferably as primitive bool)
Perhaps because initState() is in the State class, which your StatefulWidget can't call. So your entire state should be in your State class to permit that.