为什么即使Widget不可见,State的build()方法也会被调用?

时间:2017-11-02 12:59:54

标签: flutter

此示例Flutter应用程序包含一个抽屉和两个可以使用抽屉导航的“页面”(脚手架):

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对象,并且即使Widget当前不可见,它的build()方法也会不断被调用。

显然出现了问题(?) - 这里发生了什么?

2 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

Navigator.of(context).pushNamed('/');这样的方法通常会创建并“推送”新的小部件。这可能是你为何拥有新州的原因。

您可以在Stocks app

中找到抽屉的示例