Flutter Change Notifier dispose individual listener - flutter

I'm currently adding a listener to a screen like this:
#override
void initState() {
person.addListener(() {
doSomething();
});
super.initState();
}
This works, but I have difficulties with correctly disposing the listener after I will call Navigator pop.
I tried calling dispose
#override
void dispose() {
person.dispose();
super.dispose();
}
But this disposes all the listeners on "person". Which are active on other parts in the app.
Is there a possibility to assign a key to the addListener and dispose only that addListener?
Thanks.

You could say person.removeListener(yourListener) in your dispose method

Related

How to use dispose with flutter bloc?

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 need removelistener before ChangeNotifier disposed?

For example, i am call the controller.dispose() when page dispose, i also have to call the controller.removeListener?
TextEditingController _controller = TextEditingController();
#override
void initState() {
super.initState();
_controller.addListener(_listener);
}
void _listener() {
print(_controller.text);
}
#override
void dispose() {
// _controller.removeListener(_listener); //It is a must?
_controller.dispose();
super.dispose();
}
I see ChangeNotify source code about dispose
#mustCallSuper
void dispose() {
assert(_debugAssertNotDisposed());
_listeners = null;
}
I think is cleared listener, i am not need to call the removeListener method. But somebody tell me i need call the reamoveListener method before dispose method. I feel confused and want someone to tell me i am right or wrong. Thanks in advance!
Just called
_controller.dispose();
you don't need to call _controller.removeListener(_listener);

"Bad state: Stream has already been listened to" occurs when I visit screen multiple times

I'm using flutter_bluetooth_serial library and in initState() function I'm using listen to call a function. It's working fine when the app initially starts but when I visit this screen for the second time on the app I get a red screen saying "Bad state: Stream has already been listened to".
I'm new to flutter so please provide the exact code that can help me resolve this issue.
#override
void initState() {
super.initState();
widget.connection.input.listen(_onDataReceived).onDone(() {
// Example: Detect which side closed the connection
// There should be `isDisconnecting` flag to show are we are (locally)
// in middle of disconnecting process, should be set before calling
// `dispose`, `finish` or `close`, which all causes to disconnect.
// If we except the disconnection, `onDone` should be fired as result.
// If we didn't except this (no flag set), it means closing by remote.
if (isDisconnecting) {
print('Disconnecting locally!');
} else {
print('Disconnected remotely!');
}
if (this.mounted) {
setState(() {});
}
});
}
Try to override dispose() method of the state and cancel subscription within it. To do that you need to save subscription in a variable:
StreamSubscription _subscription;
#override
void initState() {
super.initState();
_subscription = widget.connection.input.listen(_onDataReceived, onDone: () {
...
});
}
override
void dispose() {
_subscription.cancel();
super.dispose();
}
Edit
If you need to subscribe to the connection.input multiple times across the app - you can transform it to broacast stream and subscribe for it. It should help. Like this:
final broadcastInput = connection.input.asBroadcastStream();
But if you need to use connection only in this widget I would recommend you to keep it inside state (not widget) and close it on dispose. It would be better lifecycle control solution.
BluetoothConnection _connection;
#override
void initState() {
super.initState();
_initConnection();
}
Future<void> _initConnection() async {
_connection = await BluetoothConnection.toAddress(address);
/// Here you can subscribe for _connection.input
...
}
#override
void dispose() {
connection;
super.dispose();
}

Removing listerers before dispose flutter

If i initialise a watcher in the initState() e.g.
textController.addListener(textTypedListener);
Do i need to manually remove the listener before I dispose of the text controller? or does the dispose automatically handle this.
eg. Options 1
#override
void dispose() {
textController.removeListener(textTypedListener);
textController.dispose();
super.dispose();
}
Option 2
#override
void dispose() {
textController.dispose();
super.dispose();
}
Which is best?
Thanks a lot.
According to the Interactive Example given in the flutter documentation of Handle changes to a text field, it's commented that calling dispose also removes the listener.
So the second option would be best.

Should codes be written before super.initState(); or after in Flutter?

Should the code that is being written to initState() function be written before super.initState(); or after?
Which one is proper:
#override
// code here
super.initState();
}
or
#override
super.initState();
// code here
}
both will work.
But if you see from any dependencies or official docs flutter, write your code in initSate() after super.initState();
#overrride
initState(){
super.initState()
//your code
}
reference to this initState
the opposite for dispose(), write your code before super.dispose();
#overrride
dispose(){
//your code
super.dispose()
}
reference to dispose
When I see #Kahoo answer, I check it by cmd + click at super.dispose and super.initstate, I found this for dispose
/// If you override this, make sure to end your method with a call to
/// super.dispose().
///
/// See also:
///
/// * [deactivate], which is called prior to [dispose].
#protected
#mustCallSuper
void dispose() {
assert(_debugLifecycleState == _StateLifecycle.ready);
assert(() {
_debugLifecycleState = _StateLifecycle.defunct;
return true;
}());
}
abstract class State :
/// If you override this, make sure your method starts with a call to
/// super.initState().
#protected
#mustCallSuper
void initState() {
assert(_debugLifecycleState == _StateLifecycle.created);
}
Both will work fine, but the better practise is to write before super.initState(), because it will do all the initialisations before creating the state widget which will help you in maintaining the check on the Widget State.
But this does not means that the second method will not keep close eye on maintaining the state, But as of better practise the First way is preferred.