I was wondering if anybody knew a way to know when an InheritedWidget was disposed?
The reason of this question is that I am doing some experiments and I am using an InheritedWidget as a provider of a BLoC. This BLoC is initialized at the InheritedWidget level, and uses a StreamController.
As it is more than recommended to close a StreamController, I am trying to find a solution.
Here is a piece of code (silly code just for experiments) to illustrate the question:
///
/// ApplicationProvider
///
/// A provider of ApplicationBloc
///
class ApplicationProvider extends InheritedWidget {
//
// Initialization of the BLoC
//
final ApplicationBloc bloc = new ApplicationBloc();
ApplicationProvider({Key key, Widget child}) : super(key: key, child: child);
@override
bool updateShouldNotify(_) => true;
static ApplicationBloc of(BuildContext context, [bool redraw = true]) {
return redraw ? (context.inheritFromWidgetOfExactType(ApplicationProvider) as ApplicationProvider).bloc
: (context.ancestorWidgetOfExactType(ApplicationProvider) as ApplicationProvider).bloc;
}
}
//
// The BLoC
//
class ApplicationBloc {
int _counter;
StreamController<int> _counterController = new StreamController<int>.broadcast();
Sink get inCounter => _counterController;
Stream<int> get outCounter => _counterController.stream;
ApplicationBloc(){
_counter = 0;
}
void increment(){
_counter++;
inCounter.add(_counter);
}
int get counter => _counter;
//
// How could I call this method ???
//
void dispose(){
_counterController.close();
}
}
So the main question is "how can I call the dispose() method of my BLoC" ?
Many thanks for your help.
Dispose is a method triggered whenever the created object from the stateful widget is removed permanently from the widget tree. It is generally overridden and called only when the state object is destroyed. Dispose releases the memory allocated to the existing variables of the state.
dispose() method called automatically from stateful if not defined. In some cases dispose is required for example in CameraPreview , Timer etc.. you have to close the stream.
InheritedWidget
behaves the same way as other Widget
do.
Their lifetime is really short: Usually not longer than one build
call.
If you want to store data for longer, InheritedWidget
is not what you want. You'll need a State
for that.
Which also means that ultimately, you can use State
's dispose for your bloc dispose.
class BlocHolder extends StatefulWidget {
final Widget child;
BlocHolder({this.child});
@override
_BlocHolderState createState() => _BlocHolderState();
}
class _BlocHolderState extends State<BlocHolder> {
final _bloc = new MyBloc();
@override
Widget build(BuildContext context) {
return MyInherited(bloc: _bloc, child: widget.child,);
}
@override
void dispose() {
_bloc.dispose();
super.dispose();
}
}
class MyInherited extends InheritedWidget {
final MyBloc bloc;
MyInherited({this.bloc, Widget child}): super(child: child);
@override
bool updateShouldNotify(InheritedWidget oldWidget) {
return oldWidget != this;
}
}
class MyBloc {
void dispose() {
}
}
Inherited widgets behave very much like stateless widgets, which also do not have a dispose
method. Inherited widgets are getting rebuilt frequently, and all the values stored inside of it would be lost (and without a proper updateShouldNotify
implementation, the dependent widget trees will also be rebuilt frequently!).
To solve this problem, you can utilize a StatefulWidget
:
import 'dart:async';
import 'package:flutter/widgets.dart';
class ApplicationProvider extends StatefulWidget {
const ApplicationProvider({Key key, this.child}) : super(key: key);
final Widget child;
@override
State<StatefulWidget> createState() => _ApplicationProviderState();
}
class _ApplicationProviderState extends State<ApplicationProvider> {
final ApplicationBloc bloc = new ApplicationBloc();
@override
void dispose() {
bloc.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
return _ApplicationProvider(
bloc: bloc,
child: widget.child,
);
}
}
class _ApplicationProvider extends InheritedWidget {
_ApplicationProvider({
Key key,
this.bloc,
Widget child,
}) : super(key: key, child: child);
final ApplicationBloc bloc;
@override
bool updateShouldNotify(_ApplicationProvider oldWidget) {
return bloc != oldWidget.bloc;
}
}
class ApplicationBloc {
ApplicationBloc of(BuildContext context) {
final _ApplicationProvider provider = context.inheritFromWidgetOfExactType(_ApplicationProvider);
return provider.bloc;
}
int _counter;
StreamController<int> _counterController = new StreamController<int>.broadcast();
Sink get inCounter => _counterController;
Stream<int> get outCounter => _counterController.stream;
ApplicationBloc() {
_counter = 0;
}
void increment() {
_counter++;
inCounter.add(_counter);
}
int get counter => _counter;
void dispose() {
_counterController.close();
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With