【问题标题】:Why does State's build() method keep get called even if Widget is not visible?为什么即使 Widget 不可见,State 的 build() 方法也会被调用?
【发布时间】:2018-04-15 00:26:33
【问题描述】:

这个示例 Flutter 应用由一个 Drawer 和两个可以使用该抽屉导航的“页面”(Scaffolds)组成:

import 'package:flutter/material.dart';

class MyTestDrawer extends StatefulWidget {
  @override
  _MyTestDrawerState createState() => new _MyTestDrawerState();
}

class _MyTestDrawerState extends State<MyTestDrawer> {
  @override
  Widget build(BuildContext context) {

    return new Drawer(child: new ListView(
        children: <Widget>[

          new ListTile(
              leading: new Icon(Icons.pregnant_woman),
              title: new Text('Homepage'),
              onTap: () {
                Navigator.of(context).pushNamed('/');
              }
          ),
          new ListTile(
              leading: new Icon(Icons.group),
              title: new Text('Second page'),
              onTap: () {
                Navigator.of(context).pushNamed('/second');
              }
          ),
          new AboutListTile(
              icon: new Icon(Icons.help)
          )
        ]
    )
    );

  }
}

final MyTestDrawer _drawer = new MyTestDrawer();


class FlutterTestApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    return new MaterialApp(
        title: 'Flutter Test',
        theme: new ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: new HomepageWidget(),
        routes: <String, WidgetBuilder> {
          '/second': (BuildContext context) => new SecondPage(),
        }
    );


  }
}


class HomepageWidget extends StatefulWidget {
  @override
  _HomepageWidgetState createState() => new _HomepageWidgetState();
}

class _HomepageWidgetState extends State<HomepageWidget> {
  @override
  Widget build(BuildContext context) {
    print('build: ' + this.toString());

    return new Scaffold(
      drawer: _drawer,
      appBar: new AppBar(title: new Text('Homepage')),
      body: new Container(
          child: new Center(child: new Text('Homepage'))
      )
    );
  }
}


class SecondPage extends StatefulWidget {
  @override
  _SecondPageState createState() => new _SecondPageState();
}

class _SecondPageState extends State<SecondPage> {
  @override
  Widget build(BuildContext context) {

    print('build: '+ this.toString());

    return new Scaffold(
        drawer: _drawer,
        appBar: new AppBar(title: new Text('Second page')),
        body: new Container(
            child: new Center(child: new Text('Second page'))
        )
    );
  }
}



void main() {
  runApp(new FlutterTestApp());
}

我在 HomepageState 和 SecondPageState build() 方法中有一个 print 调试语句。

当我运行这个应用程序并在主页第二页之间导航时,我最终会在我的日志中得到这个:

build: _HomepageWidgetState#e0d4a
build: _SecondPageState#06d69
build: _SecondPageState#9c9f7
build: _SecondPageState#db373
build: _SecondPageState#4d4ca
build: _SecondPageState#15247
build: _SecondPageState#06d69
build: _SecondPageState#9c9f7
build: _SecondPageState#db373
build: _SecondPageState#4d4ca
build: _HomepageWidgetState#0d598
build: _HomepageWidgetState#3bb96
build: _HomepageWidgetState#09270
build: _HomepageWidgetState#640bb
build: _HomepageWidgetState#6385a
build: _HomepageWidgetState#ed720
build: _HomepageWidgetState#f45da

似乎每次我在两个页面之间导航时都会创建一个新的 State 对象,并且它的 build() 方法也会不断被调用,即使 Widget 当前不可见。

显然出了点问题 (?) - 这是怎么回事?

【问题讨论】:

    标签: flutter


    【解决方案1】:

    Flutter 为您推送的每条路由创建一个 State 对象,并在您每次将新路由推送到导航器堆栈时调用其 build() 方法。您目前没有提供将任何东西从堆栈中弹出的方法。

    您可能应该避免为SecondPage 指定抽屉,而是强制用户使用后退按钮导航回主页。这将防止Navigator 历史堆栈变得任意大。

    【讨论】:

    • 感谢科林,这就是我最终使用的解决方案;只有一个带有抽屉的主页,其余的带有一个后退按钮。你的解释很有道理。所以我想如果我想有多个带有抽屉的路线,那么如果它在导航之前有一个抽屉,我就必须弹出当前路线。
    【解决方案2】:

    Navigator.of(context).pushNamed('/'); 之类的方法通常会创建并“推送”新的小部件。这可能是您拥有新状态的原因。

    你可以在Stocks app找到抽屉的例子

    【讨论】:

    • 是的,一个新的 Widget 很好......但是为什么它保留旧的引用并继续在它们上运行 build()?
    • 谢谢,当你指出我正确的方向时,我将其标记为正确 - 看起来有两个原因:1. 两个小部件共享同一个 Drawer 实例(所以我认为 Drawer 保留了引用永远活着(?))和 2. 如果您当前正在尝试导航到的页面上,则应该弹出抽屉(不要获得第二个参考)。但我认为这里的主要问题是我提到的第一个问题。
    猜你喜欢
    • 1970-01-01
    • 2020-04-08
    • 1970-01-01
    • 1970-01-01
    • 2017-08-19
    • 2021-04-16
    • 2020-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多