Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Flutter disposing my widget state object in a tabbed interface?

I have a tabbed Flutter interfaces using DefaultTabController with 3 pages, each a stateful widget. I seem to be able to switch between the first two tabs just fine, but when I tab to the 3rd page the state object for the first page gets disposed. Subsequent state updates (using setState()) then fail.

I've overridden the dispose() method of the state object for the first page so that it prints a message when disposed. It's getting disposed as soon as I hit the third tab. I can't find documentation on why Flutter disposes state objects. (Plenty on lifecycle but not the reasons for progressing through the stages.)

Nothing unusual about setting up the tabs, I don't think.

 @override
  Widget build(BuildContext context) {
    return new MaterialApp(

      home: DefaultTabController(
        length: 3,
        child: Scaffold(
          appBar: AppBar(
            title: Text(title),
            bottom: TabBar(
              tabs: [
                // Use these 3 icons on the tab bar.
                Tab(icon: Icon(Icons.tune)),
                Tab(icon: Icon(Icons.access_time)),
                Tab(icon: Icon(Icons.settings)),
              ],
            ),
          ),
          body: TabBarView(
            children: [
              // These are the 3 pages relating to to the tabs.
              ToolPage(),
              TimerPage(),
              SettingsPage(),
            ],

The pages themselves are pretty simple. No animation. Just switches and sliders, etc. I think about the only departures I've made from the code examples I've seen are that I've made the main app widget stateful, I've extended the tab pages to support wantKeepAlive() and I override wantKeepAlive to set it to true (thought that might help), and I call setState() on the first two tabs from an external object, which Android Studio flags with a weak warning. State on the first two pages gets updated when reading from a websocket this app opens to a remote server. Upon further testing I've noticed it only happens only when I tab from the first to the third page. Going from first to second or second to third does not trigger the dispose.

I would expect the State object associated with a StatefulWidget to stay around and with wantKeepAlive = true don't understand why it's being disposed when I click to the third tab, especially because it doesn't happen when I click to the second or from the second to third.

like image 627
Keith A Avatar asked Apr 25 '19 13:04

Keith A


People also ask

How do you keep state tab in flutter?

In case you want to keep the state of your screen in your TabBarView , you can use the mixin class called AutomaticKeepAliveClientMixin in your State class. After that you have to override the wantKeepAlive method and return true .

How do I turn off the tab bar in flutter?

Use IgnorePointer. It will disable the click action of tabs.

When dispose method is called in flutter?

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.


1 Answers

This happens because TabBarView doesn't always show all tabs. Some may be outside of the screen boundaries.

In that case, the default behavior is that Flutter will unmount these widgets to optimize resources.

This behavior can be changed using what Flutter calls "keep alive".

The easiest way is to use AutomaticKeepAliveClientMixin mixin on a State subclass contained inside your tab as such:

class Foo extends StatefulWidget {
  @override
  _FooState createState() => _FooState();
}

class _FooState extends State<Foo> with AutomaticKeepAliveClientMixin {
  @override
  bool wantKeepAlive = true;

  @override
  Widget build(BuildContext context) {
    super.build(context);
    return Container();
  }
}

This tells Flutter that Foo should not be disposed when it leaves the screen.

like image 154
Rémi Rousselet Avatar answered Nov 15 '22 11:11

Rémi Rousselet