热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

扑朔迷离的执行顺序:build和initState

如何解决《扑朔迷离的执行顺序:build和initState》经验,为你挑选了1个好方法。

我正在尝试创建一个“首选项”菜单,其中有三个与“共享首选项”一起存储的设置(例如“通知”)。它们将应用于SwitchListTiles。

每次选择我的设置选项卡时,都会发生错误(I / flutter(22754):引发了另一个异常:'package:flutter / src / material / switch_list_tile.dart':失败的断言:第84行pos 15:'value!= null ':不正确。)仅显示一毫秒。之后,将显示正确的设置。当我不向“ ProfileState”中初始化的变量添加默认值时,就会发生这种情况。如果它们具有默认值,则错误消失,但是在选项卡选择中,开关从“默认值”到“共享首选项”中的正确值“闪烁”。

我的假设是我的loadSettings函数在build方法之后执行。

我该如何解决?任何帮助表示赞赏。

import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Profile extends StatefulWidget {
  @override
  ProfileState createState() {
    return new ProfileState();
  }
}

class ProfileState extends State {
  bool notifications;
  bool trackHistory;
  bool instantOrders;

  @override
  void initState() {
    super.initState();
    loadSettings();
  }

  //load settings
  loadSettings() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    setState(() {
      notificatiOns= (prefs.getBool('notifications') ?? true);
      trackHistory = (prefs.getBool('trackHistory') ?? true);
      instantOrders = (prefs.getBool('instantOrders') ?? false);
    });
  }

  //set settings
  setSettings() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    prefs.setBool('notifications', notifications);
    prefs.setBool('trackHistory', trackHistory);
    prefs.setBool('instantOrders', instantOrders);
  }

  @override
  Widget build(BuildContext context) {
    return new ListView(
      children: [
        new Row(
          children: [
            new Container(
              padding: new EdgeInsets.fromLTRB(20.0, 20.0, 0.0, 8.0),
              child: new Text("General", style: new TextStyle(color: Colors.black54)),
            )
          ],
        ),
        new SwitchListTile(
          title: const Text('Receive Notifications'),
          activeColor: Colors.brown,
          value: notifications,
          onChanged: (bool value) {
            setState(() {
              notificatiOns= value;
              setSettings();
            });
          },
          secondary: const Icon(Icons.notifications, color: Colors.brown),
        ),
        new SwitchListTile(
          title: const Text('Track History of Orders'),
          activeColor: Colors.brown,
          value: trackHistory,
          onChanged: (bool value) {
            setState((){
              trackHistory = value;
              setSettings();
            });
          },
          secondary: const Icon(Icons.history, color: Colors.brown,),
        ),
        new SwitchListTile(
          title: const Text('Force instant Orders'),
          activeColor: Colors.brown,
          value: instantOrders,
          onChanged: (bool value) {
            setState((){
              instantOrders = value;
              setSettings();
            });
          },
          secondary: const Icon(Icons.fast_forward, color: Colors.brown),
        ),
        new Divider(
          height: 10.0,
          ),
        new Container(
          padding: EdgeInsets.all(32.0),
          child: new Center(
            child: new Column(
              children: [
                new TextField(
                )
              ],
            ),
          ),
        ),
        new Divider(
          height: 10.0,
        ),
        new Row(
          children: [
            new Container(
              padding: new EdgeInsets.fromLTRB(20.0, 20.0, 0.0, 20.0),
              child: new Text("License Information", style: new TextStyle(color: Colors.black54)),
            )
          ],
        ),
        new Container(
          padding: new EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 20.0) ,
          child: new RichText(
            text: new TextSpan(
              text: "With confirming our terms and conditions you accept full usage of your personal data. Yikes!",
              style: new TextStyle(color: Colors.black)
            )
          )
        )
      ]
    );
  }
}

编辑

我尝试使用Darek解决方案中推荐的FutureBuilder解决该问题。最初的错误现在已解决,但现在我又遇到了不便。每次轻按开关,该选项卡便会完全构建,这很明显。此外,开关不再平稳运行。在启动应用程序时,您还可以很快看到等待消息,这不是那么好。

这是代码中的新类:

class ProfileState extends State {
  bool notifications;
  bool trackHistory;
  bool instantOrders;
  SharedPreferences prefs;

  @override
  void initState() {

    super.initState();
    loadSettings();
  }

  //load settings
  Future loadSettings() async {
    prefs = await SharedPreferences.getInstance();
    notificatiOns= (prefs.getBool('notifications') ?? true);
    trackHistory = (prefs.getBool('trackHistory') ?? true);
    instantOrders= (prefs.getBool('instantOrders') ?? true);
  }

  //set settings
  setSettings() async {
    prefs.setBool('notifications', notifications);
    prefs.setBool('trackHistory', trackHistory);
    prefs.setBool('instantOrders', instantOrders);
  }

  @override
  Widget build(BuildContext context) {
    var profileBuilder = new FutureBuilder(
      future: loadSettings(), // a Future or null
      builder: (BuildContext context, AsyncSnapshot snapshot) {
        switch (snapshot.connectionState) {
          case ConnectionState.none:
            return new Text('No preferences');
          case ConnectionState.waiting:
            return new Text('Loading preferences');
          case ConnectionState.done:
            if (snapshot.hasError)
              return new Text('Error: ');
            else
              return new Column(
                  children: [
                    new Row(
                      children: [
                        new Container(
                          padding: new EdgeInsets.fromLTRB(20.0, 20.0, 0.0, 8.0),
                          child: new Text("General", style: new TextStyle(color: Colors.black54)),
                        )
                      ],
                    ),
                    new SwitchListTile(
                      title: const Text('Receive Notifications'),
                      activeColor: Colors.brown,
                      value: notifications,
                      onChanged: (bool value) {
                        setState(() {
                          notificatiOns= value;
                          setSettings();
                        });
                      },
                      secondary: const Icon(Icons.notifications, color: Colors.brown),
                    ),
                    new SwitchListTile(
                      title: const Text('Track History of Orders'),
                      activeColor: Colors.brown,
                      value: trackHistory,
                      onChanged: (bool value) {
                        setState((){
                          trackHistory = value;
                          setSettings();
                        });
                      },
                      secondary: const Icon(Icons.history, color: Colors.brown,),
                    ),
                    new SwitchListTile(
                      title: const Text('Force instant Orders'),
                      activeColor: Colors.brown,
                      value: instantOrders,
                      onChanged: (bool value) {
                        setState((){
                          instantOrders = value;
                          setSettings();
                        });
                      },
                      secondary: const Icon(Icons.fast_forward, color: Colors.brown),
                    ),
                    new Divider(
                      height: 10.0,
                    ),
                    new Row(
                      children: [
                        new Container(
                          padding: new EdgeInsets.fromLTRB(20.0, 20.0, 0.0, 20.0),
                          child: new Text("License Information", style: new TextStyle(color: Colors.black54)),
                        )
                      ],
                    ),
                    new Container(
                        padding: new EdgeInsets.fromLTRB(20.0, 0.0, 20.0, 20.0) ,
                        child: new RichText(
                            text: new TextSpan(
                                text: "With confirming our terms and conditions you accept full usage of your personal data. Yikes!",
                                style: new TextStyle(color: Colors.black)
                            )
                        )
                    )
                  ]
              );
        }
      },
    );
    return new Scaffold(
      body: profileBuilder,
    );


  }
}

Derek Lakin.. 6

State对象的生命周期为createState-> initState-> didChangeDependencies-> build(有关更多详细信息,请参见链接的文档)。因此,在您的情况下,这不是订购问题。实际发生的是loadSettings被调用,但是一旦它到达awaita,Future就会立即返回并继续执行调用方(请参见Dart文档中的async / await )。因此,将构建窗口小部件树并使用最初的空值,然后执行异步部分,并对变量进行初始化,这setState被称为触发重建,效果很好。

您需要使用FutureBuilder,以便您可以在Future完成后相应地构建UI:

new FutureBuilder(
  future: _calculation, // a Future or null
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none: return new Text('Press button to start');
      case ConnectionState.waiting: return new Text('Awaiting result...');
      default:
        if (snapshot.hasError)
          return new Text('Error: ${snapshot.error}');
        else
          return new Text('Result: ${snapshot.data}');
    }
  },
)

在上面的示例中,您将替换_calculationloadSettings并返回nonewaiting状态中的相关UI (后者将是带有SwitchListTiles的UI )。



1> Derek Lakin..:

State对象的生命周期为createState-> initState-> didChangeDependencies-> build(有关更多详细信息,请参见链接的文档)。因此,在您的情况下,这不是订购问题。实际发生的是loadSettings被调用,但是一旦它到达awaita,Future就会立即返回并继续执行调用方(请参见Dart文档中的async / await )。因此,将构建窗口小部件树并使用最初的空值,然后执行异步部分,并对变量进行初始化,这setState被称为触发重建,效果很好。

您需要使用FutureBuilder,以便您可以在Future完成后相应地构建UI:

new FutureBuilder(
  future: _calculation, // a Future or null
  builder: (BuildContext context, AsyncSnapshot snapshot) {
    switch (snapshot.connectionState) {
      case ConnectionState.none: return new Text('Press button to start');
      case ConnectionState.waiting: return new Text('Awaiting result...');
      default:
        if (snapshot.hasError)
          return new Text('Error: ${snapshot.error}');
        else
          return new Text('Result: ${snapshot.data}');
    }
  },
)

在上面的示例中,您将替换_calculationloadSettings并返回nonewaiting状态中的相关UI (后者将是带有SwitchListTiles的UI )。


推荐阅读
author-avatar
Zhangjingy2502870421
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有