颤振应用程序中的“setState() 或 MarkNeedsBuild() 期间调用”错误

Posted

技术标签:

【中文标题】颤振应用程序中的“setState() 或 MarkNeedsBuild() 期间调用”错误【英文标题】:"setState() or MarkNeedsBuild() called during" error in flutter app 【发布时间】:2021-04-08 21:25:18 【问题描述】:

我是 Flutter 的初学者。当我调用Settings widget 时,会发生以下错误。我尝试了从同一问题发布的所有内容,但没有任何改变。当我删除 StreamBuilder 它工作正常。但是,如果没有 StreamBuilder,我无法从 Cloud Firestore 获取数据并将其显示在设置小部件中。

这是我调用Settings widget的主屏幕。

body: FlatButton.icon(
            onPressed: () 
              Navigator.of(context)
                  .push(MaterialPageRoute(builder: (context) => Settings()));
            ,
            icon: Icon(Icons.settings),
            label: Text('User Profile')),
      );

这是设置小部件

import 'dart:math';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:flutter/material.dart';
import 'package:flutter_firebase_test/screens/services/auth.dart';
import 'package:flutter_firebase_test/shared/loading.dart';

class Settings extends StatefulWidget 
  @override
  _Settings createState() => _Settings();


class _Settings extends State<Settings> 
  AuthService _auth = new AuthService();
  @override
  Widget build(BuildContext context) 
    Color randomColor() 
      int index = 0;
      List colors = [
        Colors.red,
        Colors.blue,
        Colors.green,
        Colors.yellow,
        Colors.amber,
        Colors.deepPurple
      ];
      Random rnd = new Random();
      setState(() => index = rnd.nextInt(6));
      return colors[index];
    

    return StreamBuilder<QuerySnapshot>(
        stream: Firestore.instance.collection('users').snapshots(),
        builder: (context, snapshot) 
          if (!snapshot.hasData) 
            return Loading();
           else 
            return Scaffold(
              body: Container(
                padding: EdgeInsets.fromLTRB(30, 80, 30, 0),
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Center(
                      child: Column(
                        children: [
                          CircleAvatar(
                            backgroundColor: randomColor(),
                            //backgroundImage: AssetImage('assets/avatars/male1.jpg'),
                            radius: 60,
                            child: Text(
                              // TODO: The name will be set later!
                              "Ali"[0].toUpperCase(),
                              style: TextStyle(
                                color: Colors.black,
                                fontWeight: FontWeight.bold,
                                fontSize: 40,
                              ),
                            ),
                          ),
                          SizedBox(
                            height: 20,
                          ),
                          Text("dasdas"),
                        ],
                      ),
                    ),
                    SizedBox(
                      height: 30,
                    ),
                    Divider(
                      color: Colors.black,
                    ),
                    SizedBox(
                      height: 40,
                    ),
                    Wrap(children: [
                      Text(
                        "Name:",
                        style: TextStyle(
                          fontSize: 20,
                        ),
                      ),
                      SizedBox(
                        width: 20,
                      ),
                    ]),
                    SizedBox(
                      height: 40,
                    ),
                    Wrap(children: [
                      Text(
                        "Username:",
                        style: TextStyle(
                          fontSize: 20,
                        ),
                      ),
                      SizedBox(
                        width: 20,
                      ),
                      Text(
                        "User fullname will display here",
                        style: TextStyle(
                          fontSize: 20,
                        ),
                      ),
                    ]),
                  ],
                ),
              ),
            );
          
        );
  

flutter doctor -v结果

] Flutter (Channel stable, 1.22.5, on Microsoft Windows [Version 10.0.19042.685], locale en-US)
    • Flutter version 1.22.5 at C:\src\flutter
    • Framework revision 7891006299 (3 weeks ago), 2020-12-10 11:54:40 -0800
    • Engine revision ae90085a84
    • Dart version 2.10.4       

 
[√] android toolchain - develop for Android devices (Android SDK version 30.0.2)
    • Android SDK at C:\Users\demir\AppData\Local\Android\sdk
    • Platform android-30, build-tools 30.0.2
    • Java binary at: C:\Program Files\Android\Android Studio\jre\bin\java
    • Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b01)
    • All Android licenses accepted.

调试控制台:

The following assertion was thrown building StreamBuilder<QuerySnapshot>(dirty, state: _StreamBuilderBaseState<QuerySnapshot, AsyncSnapshot<QuerySnapshot>>#778da):
setState() or markNeedsBuild() called during build.
This Settings widget cannot be marked as needing to build because the framework is already in the process of building widgets.  A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.

    state: _StreamBuilderBaseState<QuerySnapshot, AsyncSnapshot<QuerySnapshot>>#778da
The relevant error-causing widget was
StreamBuilder<QuerySnapshot>
package:flutter_firebase_test/…/home/settings.dart:31
When the exception was thrown, this was the stack
#0      Element.markNeedsBuild.<anonymous closure>
package:flutter/…/widgets/framework.dart:4292
#1      Element.markNeedsBuild
package:flutter/…/widgets/framework.dart:4307
#2      State.setState
package:flutter/…/widgets/framework.dart:1264
#3      _Settings.build.randomColor
package:flutter_firebase_test/…/home/settings.dart:27
#4      _Settings.build.<anonymous closure>
package:flutter_firebase_test/…/home/settings.dart:47
...


【问题讨论】:

【参考方案1】:

randomColor 方法放在build 方法之外。此外,您不需要在索引变量上调用 setState,因为它在该方法中是本地的

Color randomColor() 
  int index = 0;
  List colors = [
    Colors.red,
    Colors.blue,
    Colors.green,
    Colors.yellow,
    Colors.amber,
    Colors.deepPurple
  ];
  Random rnd = new Random();
  index = rnd.nextInt(6);
  return colors[index];


// ...

@override
Widget build(BuildContext context) 

【讨论】:

你太棒了。我已经为这个错误苦苦挣扎了 2 天。太感谢了。但是,由于我是一名学生,我想问为什么我应该将 randomColor 方法移到构建小部件之外?发生了什么变化? 每次调用 setState 时,都会调用 build 方法。所以这将在递归模式下发生,直到错误发生。 如果您的问题得到解答,请将答案标记为正确并投票以帮助未来的读者 再次感谢。我排除了答案。 很高兴它有帮助!快乐编码

以上是关于颤振应用程序中的“setState() 或 MarkNeedsBuild() 期间调用”错误的主要内容,如果未能解决你的问题,请参考以下文章

颤振中的亮/暗模式

如何停止颤振应用程序中的firebase错误

如何根据检测到颤振应用程序中的锁定或关闭屏幕采取行动

FLUTTER -iOS 中最近应用程序中的默认颤振图标

在颤振中如何清除栏中的通知?

无法在我的颤振演示应用程序中的列表视图中显示网格视图