为什么 Flutter 会在选项卡式界面中处理我的小部件状态对象?

Kei*_*h A 6 tabs dispose flutter

我有一个选项卡式 Flutter 界面,使用 DefaultTabController 和 3 个页面,每个页面都是一个有状态的小部件。我似乎能够在前两个选项卡之间切换就好了,但是当我切换到第 3 页时,第一页的状态对象被处理掉了。随后的状态更新(使用 setState())然后失败。

我已经覆盖了第一页状态对象的 dispose() 方法,以便它在处理时打印一条消息。我一点击第三个标签,它就会被处理掉。我找不到有关 Flutter 为什么处理状态对象的文档。(生命周期有很多,但不是通过各个阶段的原因。)

我不认为设置标签没有什么不寻常的地方。

 @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(),
            ],
Run Code Online (Sandbox Code Playgroud)

页面本身非常简单。没有动画。只是开关和滑块等。我认为我从我所看到的代码示例中所做的唯一偏离是,我使主应用程序小部件有状态,我扩展了标签页以支持 wantKeepAlive() 和我覆盖了 wantKeepAlive 以将其设置为 true(认为这可能会有所帮助),并在来自外部对象的前两个选项卡上调用 setState(),Android Studio 将其标记为弱警告。当从这个应用程序打开到远程服务器的 websocket 读取时,前两页上的状态会更新。经过进一步的测试,我注意到只有当我从第一页跳到第三页时才会发生这种情况。从第一个到第二个或第二个到第三个不会触发处置。

我希望与 StatefulWidget 关联的 State 对象留在周围,并且 wantKeepAlive = true 不明白为什么当我点击第三个选项卡时它会被处理,特别是因为当我点击第二个或从第二到第三。

Rém*_*let 6

发生这种情况是因为TabBarView并不总是显示所有选项卡。有些可能在屏幕边界之外。

在这种情况下,默认行为是 Flutter 将卸载这些小部件以优化资源。

这种行为可以使用 Flutter 所说的“保持活动”来改变。

最简单的方法是在选项卡中包含AutomaticKeepAliveClientMixinState子类上使用mixin ,如下所示:

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();
  }
}
Run Code Online (Sandbox Code Playgroud)

这告诉 FlutterFoo当它离开屏幕时不应被处理。