flutter 为什么initState()被调用两次?

8xiog9wr  于 2023-02-16  发布在  Flutter
关注(0)|答案(4)|浏览(731)

initState()在我路由到的第一个微件上被调用两次。
我删除了initState()方法中的所有方法调用和工作,以排除它以某种方式调用自身的可能性,它所做的只是调用super.initState()。
routes.dart:

final routes = {
  '/login' : (BuildContext context) => new LoginPage(),
  '/' : (BuildContext context) => new LoginPage()
};

main.dart:

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Personnel Ledger',
      initialRoute: '/login',
      routes: routes,
      theme: ThemeData(
        scaffoldBackgroundColor: Color(0xFF30778B)
      ),
    );
  }
}

LoginPage.dart:

class LoginPage extends StatefulWidget {
  @override
  LoginPageState createState() => LoginPageState();
}

class LoginPageState extends State<LoginPage> {
  TextEditingController emailTextfieldCtrl;
  TextEditingController passwordTextfieldCtrl;
  AuthHttpService authHttpService;
  bool loggaInDisabled;
  Widget invalidCredentialsText;

  @override
  void initState() {
    super.initState();
    // setInvalidCredentialsTextVisibleWithoutSetState(false);
    // authHttpService = new AuthHttpService();
    // emailTextfieldCtrl = new TextEditingController();
    // passwordTextfieldCtrl = new TextEditingController();
    loggaInDisabled = true;
    // refreshApplicationAccessToken();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomPadding: false,
      body: SafeArea(
        child: Stack(
          children: <Widget>[
            Container(
              decoration: BoxDecoration(
                  gradient: LinearGradient(
                      begin: Alignment.topLeft,
                      end: Alignment.bottomRight,
                      colors: [Color(0xFF30778B), Color(0xFF2F3648)])),
              child: Center(
                child: Stack(
                  children: <Widget>[
                    Column(
                      children: <Widget>[
                        Spacer(
                          flex: 11,
                        ),
                        Flexible(
                          flex: 50,
                          child: Container(
                            child: Image.asset("assets/knowe-logo.png"),
                          ),
                        ),
                      ],
                    ),
                    Column(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Spacer(
                          flex: 35,
                        ),
                        Flexible(
                          flex: 10,
                          child: Container(
                            child: Row(
                              children: <Widget>[
                                Spacer(
                                  flex: 1,
                                ),
                                Flexible(
                                  flex: 7,
                                  child: Theme(
                                    data:
                                        ThemeData(hintColor: Color(0xFF9E9C9C)),
                                    child: TextField(
                                      style:
                                          TextStyle(color: Color(0xFF9E9C9C)),
                                      cursorColor: Color(0xFF9E9C9C),
                                      controller: emailTextfieldCtrl,
                                      onChanged: emailTextfieldChanged,
                                      decoration: InputDecoration(
                                          prefixIcon: Icon(
                                            Icons.person,
                                            size: 30,
                                            color: Color(0xFF9E9C9C),
                                          ),
                                          labelText: "Email",
                                          border: new UnderlineInputBorder(
                                              borderSide: BorderSide(
                                                  color: Color(0xFF9E9C9C),
                                                  style: BorderStyle.solid,
                                                  width: 2))),
                                    ),
                                  ),
                                ),
                                Spacer(
                                  flex: 1,
                                )
                              ],
                            ),
                          ),
                        ),
                        Flexible(
                          flex: 10,
                          child: Container(
                            margin: EdgeInsets.only(top: 5),
                            child: Row(
                              children: <Widget>[
                                Spacer(
                                  flex: 1,
                                ),
                                Flexible(
                                  flex: 7,
                                  child: Theme(
                                    data:
                                        ThemeData(hintColor: Color(0xFF9E9C9C)),
                                    child: TextField(
                                      obscureText: true,
                                      style:
                                          TextStyle(color: Color(0xFF9E9C9C)),
                                      cursorColor: Color(0xFF9E9C9C),
                                      controller: passwordTextfieldCtrl,
                                      onChanged: passwordTextfieldChanged,
                                      decoration: InputDecoration(
                                          prefixIcon: Icon(
                                            Icons.lock,
                                            size: 26,
                                            color: Color(0xFF9E9C9C),
                                          ),
                                          labelText: "Lösenord",
                                          border: new UnderlineInputBorder(
                                              borderSide: BorderSide(
                                                  color: Color(0xFF9E9C9C),
                                                  style: BorderStyle.solid,
                                                  width: 2))),
                                    ),
                                  ),
                                ),
                                Spacer(flex: 1)
                              ],
                            ),
                          ),
                        ),
                        Flexible(
                            flex: 10,
                            child: Container(
                              child: invalidCredentialsText,
                            )),
                        Flexible(
                          flex: 20,
                          child: Container(
                            margin: EdgeInsets.only(top: 0),
                            child: Row(
                              children: <Widget>[
                                Spacer(
                                  flex: 1,
                                ),
                                Expanded(
                                  flex: 7,
                                  child: Container(
                                    height: 50,
                                    child: RaisedButton(
                                      disabledColor: Color(0xff395A52),
                                      child: Text(
                                        "Logga in",
                                        style: TextStyle(
                                            color: loggaInDisabled
                                                ? Color(0xff7a7a7a)
                                                : Colors.white),
                                      ),
                                      onPressed: loggaInDisabled
                                          ? null
                                          : loggaInPressed,
                                      color: Color(0xff10846D),
                                    ),
                                  ),
                                ),
                                Spacer(flex: 1)
                              ],
                            ),
                          ),
                        ),
                        Container(
                          margin: EdgeInsets.only(top: 7.5),
                          child: InkWell(
                            child: Text(
                              "Glömt lösenord?",
                              style: TextStyle(color: Color(0xFF9E9C9C)),
                            ),
                            onTap: glomtLosenordPressed,
                          ),
                        ),
                        Spacer(
                          flex: 10,
                        ),
                      ],
                    )
                  ],
                ),
              ),
            ),
            Column(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.end,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: <Widget>[
                Expanded(
                  child: Column(
                    mainAxisSize: MainAxisSize.max,
                    mainAxisAlignment: MainAxisAlignment.end,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: <Widget>[
                      Container(
                        alignment: Alignment.bottomLeft,
                        padding: EdgeInsets.only(left: 15, bottom: 10),
                        color: Colors.transparent,
                        child: InkWell(
                          onTap: privacyPolicyTapped,
                          child: Text("Privacy policy",
                              style: TextStyle(
                                  color: Color(0xFF9E9C9C),
                                  fontSize: 15,
                                  decoration: TextDecoration.underline)),
                        ),
                      )
                    ],
                  ),
                )
              ],
            )
          ],
        ),
      ),
    );
  }

  setInvalidCredentialsTextVisible(bool show) {
    setState(() {
      if (show)
        invalidCredentialsText = Row(
          children: <Widget>[
            Spacer(flex: 1),
            Flexible(
              flex: 7,
              child: Column(
                children: <Widget>[
                  Flexible(
                    flex: 4,
                    child: Container(
                      alignment: Alignment.centerLeft,
                      child: Row(
                        children: <Widget>[
                          Flexible(
                            flex: 1,
                            child: Icon(
                              Icons.error,
                              size: 20,
                              color: Color(0xFF9E9C9C),
                            ),
                          ),
                          Flexible(
                            flex: 5,
                            child: Container(
                              padding: EdgeInsets.only(left: 2.5),
                              child: Text(
                                "Invalid email or password",
                                style: TextStyle(color: Color(0xFF9E9C9C)),
                              ),
                            ),
                          )
                        ],
                      ),
                    ),
                  ),
                  Spacer(
                    flex: 2,
                  )
                ],
              ),
            ),
            Spacer(flex: 1)
          ],
        );
      else
        invalidCredentialsText = Row(
          children: <Widget>[
            Spacer(flex: 1),
            Flexible(
              flex: 7,
              child: Column(
                children: <Widget>[
                  Flexible(
                    flex: 3,
                    child: Container(
                      alignment: Alignment.centerLeft,
                      child: Row(
                        children: <Widget>[
                          Flexible(
                            flex: 1,
                            child: Icon(
                              Icons.error,
                              size: 20,
                              color: Color(0x009E9C9C),
                            ),
                          ),
                          Flexible(
                            flex: 5,
                            child: Container(
                              padding: EdgeInsets.only(left: 2.5),
                              child: Text(
                                "",
                                style: TextStyle(color: Color(0xFF9E9C9C)),
                              ),
                            ),
                          )
                        ],
                      ),
                    ),
                  ),
                  Spacer(
                    flex: 2,
                  )
                ],
              ),
            ),
            Spacer(flex: 1)
          ],
        );
    });
  }

  setInvalidCredentialsTextVisibleWithoutSetState(bool show) {
    if (show)
      invalidCredentialsText = Row(
        children: <Widget>[
          Spacer(flex: 1),
          Flexible(
            flex: 7,
            child: Column(
              children: <Widget>[
                Flexible(
                  flex: 4,
                  child: Container(
                    alignment: Alignment.centerLeft,
                    child: Row(
                      children: <Widget>[
                        Flexible(
                          flex: 1,
                          child: Icon(
                            Icons.error,
                            size: 20,
                            color: Color(0xFF9E9C9C),
                          ),
                        ),
                        Flexible(
                          flex: 5,
                          child: Container(
                            padding: EdgeInsets.only(left: 2.5),
                            child: Text(
                              "Invalid email or password",
                              style: TextStyle(color: Color(0xFF9E9C9C)),
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                ),
                Spacer(
                  flex: 2,
                )
              ],
            ),
          ),
          Spacer(flex: 1)
        ],
      );
    else
      invalidCredentialsText = Row(
        children: <Widget>[
          Spacer(flex: 1),
          Flexible(
            flex: 7,
            child: Column(
              children: <Widget>[
                Flexible(
                  flex: 3,
                  child: Container(
                    alignment: Alignment.centerLeft,
                    child: Row(
                      children: <Widget>[
                        Flexible(
                          flex: 1,
                          child: Icon(
                            Icons.error,
                            size: 20,
                            color: Color(0x009E9C9C),
                          ),
                        ),
                        Flexible(
                          flex: 5,
                          child: Container(
                            padding: EdgeInsets.only(left: 2.5),
                            child: Text(
                              "",
                              style: TextStyle(color: Color(0xFF9E9C9C)),
                            ),
                          ),
                        )
                      ],
                    ),
                  ),
                ),
                Spacer(
                  flex: 2,
                )
              ],
            ),
          ),
          Spacer(flex: 1)
        ],
      );
  }

  privacyPolicyTapped() {
    launch("https://www.knowe.se/policy.html");
  }

  emailTextfieldChanged(String newEmail) {
    setState(() {
      loggaInDisabled = shouldDisableLoggaIn();
    });
  }

  passwordTextfieldChanged(String newPassword) {
    setState(() {
      loggaInDisabled = shouldDisableLoggaIn();
    });
  }

  bool shouldDisableLoggaIn() {
    var email = emailTextfieldCtrl.text;
    var password = passwordTextfieldCtrl.text;
    return !(email != null &&
        email != "" &&
        password != null &&
        password != "");
  }

  loggaInPressed() {
    logIn();
  }

  logIn() {
    var email = emailTextfieldCtrl.text;
    var password = passwordTextfieldCtrl.text;
    var appId = "4d45d54d45d45dd45d45d54d54d54d54";
    var response = authHttpService.logIn(email, password, appId);
    onLoading();
    response
        .then((response) async {
          Navigator.pop(context);
          if (response.statusCode == 200) {
            setInvalidCredentialsTextVisible(false);
            var tokensModel = TokensModel.fromJson(json.decode(response.body));
            final prefs = await SharedPreferences.getInstance();
            prefs.setString("RefreshToken", tokensModel.refreshToken);
            prefs.setString(
                "ApplicationAccessToken", tokensModel.appAccessToken);
            navigateToMainMenuPage();
          } else
            setInvalidCredentialsTextVisible(true);
        })
        .timeout(Duration(seconds: 10))
        .catchError((error) {
          Navigator.pop(context);
          showMessageDialog(
              "Fel vid inloggning", "Kunde inte få kontakt med servern.");
        });
  }

  configureFCM() {
    // var fcmHelper = new FCMHelper();
    // fcmHelper.configureFCM(context);
    // fcmHelper.registerFCMToken(userModel);
  }

  glomtLosenordPressed() {
    navigateToResetPasswordPage();
  }

  refreshApplicationAccessToken() async {
    var prefs = await SharedPreferences.getInstance();
    var refreshToken = prefs.getString("RefreshToken");
    if (refreshToken != null && refreshToken != "") {
      var response =
          authHttpService.refreshApplicationAccessToken(refreshToken);
      onLoading();
      response
          .then((response) async {
            Navigator.pop(context);
            if (response.statusCode == 200) {
              var tokensModel =
                  TokensModel.fromJson(json.decode(response.body));
              var applicationAccessToken = tokensModel.appAccessToken;
              var prefs = await SharedPreferences.getInstance();
              prefs.setString("ApplicationAccessToken", applicationAccessToken);
              navigateToMainMenuPage();
            } else
              showMessageDialog("Inloggningssessionen utgången",
                  "Logga in igen med dina uppgifter.");
          })
          .timeout(Duration(seconds: 10))
          .catchError((error) {
            Navigator.pop(context);
            showMessageDialog(
                "Fel vid inloggning", "Kunde inte få kontakt med servern.");
          });
    }
  }

  navigateToMainMenuPage() {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => MainMenuPage()),
    );
  }

  navigateToResetPasswordPage() {
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => ResetPasswordPage()),
    );
  }

  void onLoading() {
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (_) => Scaffold(
          backgroundColor: Color.fromRGBO(0, 0, 0, 0.25),
          body: Center(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              children: <Widget>[
                Container(
                    width: 40,
                    height: 40,
                    child: CircularProgressIndicator(strokeWidth: 5)),
                Container(
                  margin: EdgeInsets.only(top: 15),
                  child: Text(
                    "Loggar in...",
                    style: TextStyle(color: Colors.white, fontSize: 20),
                  ),
                )
              ],
            ),
          )),
    );
  }

  void showMessageDialog(String title, String body) {
    try {
      showDialog(
          context: context,
          builder: (BuildContext context) {
            return AlertDialog(
              title: new Text(title),
              content: new Text(body),
            );
          });
    } catch (e) {
      print(e.toString());
    }
  }
}

实际结果:调用了两次LoginPage中的initState()方法。
预期成果和目标:initState()只应调用一次。

a8jjtwal

a8jjtwal1#

这是两个事实的结合:

  • 每个路由是完全独立的。/不与/login共享状态,因此从//login将从/login触发LoginPage上的initState
  • initialRoute: '/login'并不意味着应用程序 * 直接 * 在/login上启动。

initialRoute参数设置为/foo/bar后,应用程序将以以下路线历史记录启动:

  1. x1米11米1x
  2. /foo
  3. /foo/bar
    因此,即使您具有initialRoute属性,/仍然会被推送。
yrwegjxp

yrwegjxp2#

我也遇到过同样的问题。我将分享我从自己的研究中学到的东西。

  • 当打开一个深度链接时,flutter路由器会重新创建应用程序之前的所有路由器/历史状态。
  • 这意味着后退按钮可以返回用户到达那里所需的所有屏幕,即使它是通过深度链接到达那里的。
  • 这种行为对于移动设备是有意义的。但是,在Web上,这种行为是不希望的。
  • 如果我们加载深度链接,例如:http://domain/s/lorem-ipsum/all/posts如果每个路由级别定义了自己的屏幕,则我们最终会初始化它
  • 如果您碰巧在所有级别上都有相同的组件,这又会导致5组重复的API调用,这是完全不可接受的
  • 因此,我们可以使用onGenerateInitialRoutes来防止这种行为发生。
  • 默认的历史堆栈被只有一个状态的路由器/历史堆栈覆盖
    • 主省道**
...
return MaterialApp(
  ...
  initialRoute: user != null ? '/' : '/login',
  
  // The default history stack is overridden with a router/history stack with just one state
  // In this case I used fluro but any other onGenerateRoute method will do the trick
  onGenerateInitialRoutes: (initialRoute) =>
      [appRouter.generator(RouteSettings(name: initialRoute))!],
  onGenerateRoute: appRouter.generator,
);
    • 路由器. dart**
final appRouter = FluroRouter();

void defineAppRoutes() {
  final routes = {
    // Auth
    '/login': LoginPage(),
    '/register': RegisterPage(),

    // Pages
    '/': MainFeed(),
    '/s': MainFeed(),
    '/s/:spaceId': MainFeed(),
    '/s/:spaceId/:activityId': MainFeed(),
    '/s/:spaceId/:activityId/posts': MainFeed(),
    ... many more such routes
  };

  routes.forEach((route, page) {
    appRouter.define(route, handler: Handler(
      handlerFunc: (BuildContext? context, Map<String, List<String>> params) =>
      page,
    ));
  });

  // Not found
  appRouter.notFoundHandler = Handler(
      handlerFunc: (BuildContext? context, Map<String, dynamic> params) {
        return NotFoundPage();
      });
}
    • 性能/计费问题**

你们中的一些人可能正在使用Firebase,并且可能计划运行一个流量很大的应用程序。因此,注意你的路由器的功能是非常重要的。你可能会发送更多的数据请求,而不是你第一次查看应用程序时实际需要加载的数据。特别是对于在网络上共享链接,如果你不优化你的API调用,这可能会导致成本高昂。由于Firebase是通过websockets来完成所有任务的,所以请确保您可以在所有API调用中放置print语句,或者您也可以在开发过程中切换到json-server,以便在开发者工具中更好地查看HTTP调用。有很多方法可以处理这种优化。首先重要的是要了解您的API调用以及调用的数量。我能够使用我的应用程序的未优化版本在3 - 4个工作小时内生成15K的api调用。
我还在学习这些东西,所以如果我用错了一些术语,请原谅我。让我知道我如何改进这个答案。希望它能帮助你。

ijxebb2r

ijxebb2r3#

我在所有的flutter web路径上都有一个不同的双页加载的根本原因,我不知道这是如何进入web文件夹中的index.html文件的,但是如果你看到从void main()函数到构建MaterialApp的所有操作都执行了两次,请检查你的index.html文件中是否有这个javascript链接:
<script src="main.dart.js" type="application/javascript"></script>
如果您在web/index.html文件中发现该内容,请将其删除
如果您看到以下内容,则表明您的index.html中存在错误的脚本引用

Flutter Web Bootstrap: Auto
Flutter Web Bootstrap: Programmatic

在应用程序的console.log语句中。

t5zmwmid

t5zmwmid4#

如果您使用的是获取依赖项和GetMaterialApp,而不是MaterialApp和initialRoute,请执行以下步骤。
1.清洁工程
1.删除build文件夹
1.在终端中=〉pub获取
1.问题已解决

相关问题