为什么FutureBuilder被多次调用?

时间:2020-05-14 16:10:27

标签: flutter dart layout

不好意思,我是Flutter的新手。

我正在做的课程正在练习,并且我遇到以下情况:

我有一个视图,其中可以使用方法getDataArrayFutureBuilder)使用Web服务,并且我只希望在访问此视图时仅执行一次。

我也有一个TextFieldFutureBuilder,而TextFieldbuild()中。我的widgetStatefulWidget,因为需要重绘它以显示我的TextField的字符计数器,所以我认为这就是每次键入{{1} },然后再次调用build

我该如何解决?

FutureBuilder

5 个答案:

答案 0 :(得分:4)

窗口小部件build()方法中的任何内容都可以随时触发-这就是说,您不应依赖任何可能对其产生影响的关键因素。例如,打开键盘或关闭键盘就足以触发对小部件上的build()的多次调用。

您的FutureBuilder只是树上的一个小部件,因此,它在重建时(例如,每当您在TextField上键入时)都将调用您的getDataArray()因为它实际上并不真正知道它是否已经被调用。

如果只想一次将其命名为 ,则可以将其分配给州议员,然后将其分配给您的FutureBuilder。只要该状态在小部件树上存在,就将被保留。

例如,如果您只想在每个状态生命周期中调用它,则可以在initState()上进行分配;例如,如果您希望在依赖项发生变化时随时刷新该调用,可以在didChangeDependencies()上进行分配。

 class Pagina3State extends State<Pagina3> {
   Future myFuture;

  @override
  void initState() {
     myFuture = getDataArray();
  }

  @override
   Widget build(BuildContext context) {

       child: FutureBuilder(
              future: myFuture,
      )
   }
}

答案 1 :(得分:1)

您可以创建一个返回futureBuilder的变量,因此,当您调用setState时,只有小部件可以重建,而变量则不需要,因此可以解决您的问题。

 Widget futureWidget;

  @override
  void initState() {
    futureWidget = FutureBuilder(
      future: callme(),
      builder: (_, sanpshot) {
        print("future method call");
        if (sanpshot.hasData) {
          return Text(sanpshot.data.toString());
        }
        return CircularProgressIndicator();
      },
    );
    super.initState();
  }

  callme() async {
    await Future.delayed(Duration(seconds: 1));
    return "success";
  }

  @override
  Widget build(BuildContext context) {
    print("build method call");
    return Scaffold(
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          RaisedButton(
            child: Text("press"),
            onPressed: () {
              setState(() {});
            },
          ),
          futureWidget,
        ],
      ),
    );
  }

答案 2 :(得分:0)

按照 Miguel 的建议,您应该将您的未来分配给 pip 范围之外的变量,以便它只运行一次。

请注意,从 Dart 2.0 开始,您可以使用 lazy initializationlate final variables 以更短的方式编写此代码:

build()

答案 3 :(得分:-1)

那是因为您在文本字段操作中使用了setstate,它会重建所有内容。我的一个应用程序也遇到了类似的问题,并且使用了bool来避免它,我将其命名为firstRun,如果确实是这样,那么我会在future builder中调用我的future函数,如果不是的话,我将其设为空,如ode示例下面。但是我不确定这是最好的方法,您还需要在某个地方(也许是在初始化状态)将该布尔值设为虚假;

bool firstRun = true;

 @override
    Widget build(BuildContext context) {...
                            ...
                             onChanged: (valor) {
                        firstRun = false;
                        setState(() {
                            _input = valor;
                        });
                        },
                      .....
                     FutureBuilder(
                            future: firtRun ? getDataArray() : null,
                            builder: (...

答案 4 :(得分:-1)

问题的解决方案是在未来的构建器事件中添加延迟。 连接发生在待机期间,未触发 initstate

 _initializeFirebase() async {
    //ADD DURATION
   await Future.delayed(Duration(seconds: 1));
   return Firebase.initializeApp();
 }

运行 Future Builder

return FutureBuilder(
  // Initialize FlutterFire
  future: _initializeFirebase(),
  builder: (context, snapshot) {
    // Check for errors
    if (snapshot.hasError) {
      return Center(
        child: CircularProgressIndicator(),
      );
    }
    // Once complete, show your application
    if (snapshot.connectionState == ConnectionState.done) {
      return MaterialApp(
          debugShowCheckedModeBanner: false,
          title: 'Chat Application',
          theme: ThemeData(
            primarySwatch: Colors.blue,
          ),
          initialRoute: SignScreen.routeName,
          routes: {
            SignScreen.routeName: (content) => SignScreen(),
            ChatScreen.routeName: (content) => ChatScreen(),
            LoginScreen.routeName: (content) => LoginScreen(),
            RegisterScreen.routeName: (content) => RegisterScreen(),
          });
    }

    // Otherwise, show something whilst waiting for initialization to complete
    return Center(
      child: CircularProgressIndicator(),
    );
  },
);