Flutter Error

Flutter error: setState() called after dispose()

When building apps with Flutter framework you will often encounter this common error “Unhandled Exception: setState() called after dispose() or during build.” This exception is related to something called lifecycle state execution process. It simply refers to the various built in methods Flutter calls when an activity is about to be rendered, when changes occur in a particular widget and when an activity is about to be destroyed or dispose.

Such bugs are displayed on the console as:

Unhandled Exception: setState() called after dispose()
setState() or markneedsbuild() called during build
lifecycle state: defunct, not mounted

The full error message looks like:

E/flutter ( 7586): [ERROR:flutter/lib/ui/ui_dart_state.cc(198)] 
Unhandled Exception: setState() called after dispose(): 
_Track#37715(lifecycle state: defunct, not mounted)
E/flutter ( 7586): This error happens if you call setState() 
on a State object for a widget that no longer appears in the widget tree 
(e.g., whose parent widget no longer includes the widget in its build).
This error can occur when code calls setState() from a timer or an animation callback.

Why these errors? The setState() method needs to be called to rebuild a widget. That’s when you want certain changes to reflect on a particular widget. Let say for example, you have a stateful activity with the Text(“hello world”) and you want the text to change to “solve flutter error” then you have to call the setState() method. What about the dispose() method? Flutter calls it when a particular activity is about to be destroyed. So guess what will happen when you call setState() method on an activity that is destroyed? It will surely lead to an error.

Error: setState() called after dispose(): _addchannelState#86401(lifecycle state: defunct, not mounted) happens when setState() method is called on a state widget object that is no longer available in the  widget tree. This is usually as a result of calling setState() in a method that execute after some duration, timer or an animation callback. Also, if your activity has an active scheduled or listener that could work even when you navigate to a different screen, it will throw the above error when you call setState() when in the listener after the activity is destroyed.

Solution from the Error message:

If you open your console and take a good look at the error message, you could see the solution in the message.

E/flutter ( 7586): The preferred solution is to cancel the timer or stop listening to
the animation in the dispose() callback. Another solution is to check the 
"mounted" property of this object before calling setState() to ensure the object is still in the tree.
E/flutter ( 7586): This error might indicate a memory leak if setState()
is being called because another object is retaining a reference to this 
State object after it has been removed from the tree. To avoid memory leaks, 
consider breaking the reference to this object during dispose().

Solution One: Cancel and clear the Timer before disposing an activity if Error is due to Timer:

If the activity that calls the timer is destroyed, the timer will still work by executing some methods periodically. Before navigating to a different page, you’ve to cancel, dispose and clear the timer to avoid getting such error as shown below:

var timerVariable;

timerVariable = Timer.periodic(Duration(seconds: 3), (timerVariable) {
       // this block might include your business logic
      // You might have called setState() here to refresh or build a widget/UI
      
});

The solution is to cancel and dispose the timer before destroying the activity.

@override
void dispose() {
    timer.cancel(); //cancel the active periodic task
    timer; //clear the timer variable, this will set it to null
    super.dispose(); // then finally destroy the activity
}

Check also, How to solve null check operator used on null value?

Solution Two: If you have a Listener, cancel it before disposing an activity

If you have a listener of any kind, you have to cancel it before destroying the activity. For example, I have a WebSocket listener that will not closed even after the activity that is listening to it is destroyed. You could have any kind of a listener which might not be a WebSocket but I just want you to get the scenario.

late IOWebSocketChannel channel;

channel = IOWebSocketChannel.connect(Uri.parse(url here));
channel.stream.listen((message) async {
    //you may have called the setState() method here.
});

Then inside the dispose() lifecycle state, we have to close the connection to avoid getting above error when the activity is closed.

@override
void dispose() {
    channel.sink.close(); //close the connection before you dispose
    channel.sink;
    channel;  // clear the channel
    super.dispose();
}

Check also, How to conditionally show widget in flutter?

Solution Three: Check mount before calling setState

If all the above solutions doesn’t work for you, then this will. You first needs to check if your activity is mounted or not before calling setState as shown below.

if (mounted) {
  setState(() {
    // Your state update code goes here
  });
}

Or:

if (!mounted) return;

  setState(() {
    // state update code goes here
  });

We first checked the mounted property of the activity or the state class to see if it’s mounted before calling setState() else we don’t. This is the best way to solve “Unhandled Exception: setState() called after dispose()” error in Flutter because the building of the widget depends on the mounted property.

Solution Four: Change the order of super constructor call in initState()      

Wrong code to avoid:

@override
  void initState() {
 // calling state before the super.iniState() call will not work
      setState(() {
    
      });

  super.initState();  
}

Right code to implement:

@override
  void initState() {
    super.initState();
    setState(() {
      // update widget here
    });
  }

The important thing to note here is that Flutter follows a life-cycle state call for all it activities. Therefore, you need to be careful of the order of calling super constructor method in each state method. Within the initState(), you always have to make sure you call super.initState() first before your logic.

Also, see how to fix flutter error: Null check operator used on a null value – flutter.

Related Posts

disable back button flutter

Override Or Disable Back Button Flutter Appbar – The Easy Way

Learn how to override/disable back button pressed in flutter applications to make your app standout from the rest. Why because, whiles users are interacting with your app, they…

disable back button flutter

Solve the method ‘setState’ isn’t defined for the class MyApp error in Flutter

You can solve the error The method ‘setState’ isn’t defined for the class MyApp error in Flutter by simply creating your own StatefulWidget widget. The main reason whey…

disable back button flutter

How to Shift Focus to Next TextField in Flutter

Learn how to shift focus to the next TextField or TextFormField in flutter applications. The whole idea is that when you’re done typing text in one TextField, we…

working with list in Dart/Flutter

Null check operator used on a null value – flutter

The “Null check operator used on a null value” error occurs in flutter apps when you unintentionally access a variable that has a null value. For example, if…