Flutter 数据显示为空,除非我做了一个小更改以强制热重新加载。为什么不是';一开始不是吗?

Flutter 数据显示为空,除非我做了一个小更改以强制热重新加载。为什么不是';一开始不是吗?,flutter,dart,Flutter,Dart,所以我一直在摆弄Flitter,试图创建一个基本的应用程序来看看它是如何工作的,我有一个屏幕,可以显示单个注册用户的详细信息。问题是,当我第一次导航到屏幕时,“user”对象为空,只有在我做了一些小的更改(比如对一些文本进行了强制重新加载)时,用户数据才会像变魔术一样出现 下面是我的getUser函数,它似乎按预期工作: Future<User> getUser() async { final UserDao userDao = UserDao(); final String

所以我一直在摆弄Flitter,试图创建一个基本的应用程序来看看它是如何工作的,我有一个屏幕,可以显示单个注册用户的详细信息。问题是,当我第一次导航到屏幕时,“user”对象为空,只有在我做了一些小的更改(比如对一些文本进行了强制重新加载)时,用户数据才会像变魔术一样出现

下面是我的getUser函数,它似乎按预期工作:

Future<User> getUser() async {
  final UserDao userDao = UserDao();
  final String authenticationToken = await userDao.getUserToken(0);
  final response = await http.get(
    'http://vps746196.ovh.net/api/user/',
    headers: {HttpHeaders.authorizationHeader: 'token $authenticationToken'},
  );
  final responseJson = json.decode(response.body);
  print(responseJson[0]);
  return User.fromDatabaseJson(responseJson[0]);
}
Future getUser()异步{
final UserDao UserDao=UserDao();
最终字符串authenticationToken=wait userDao.getUserToken(0);
最终响应=等待http.get(
'http://vps746196.ovh.net/api/user/',
标头:{HttpHeaders.authorizationHeader:'token$authenticationToken'},
);
final responseJson=json.decode(response.body);
打印(responseJson[0]);
返回User.fromDatabaseJson(responseJson[0]);
}
下面是我在用户屏幕上的操作:

class UserScreen extends StatefulWidget {

  @override
  _UserScreenState createState() => _UserScreenState();
}

class _UserScreenState extends State<UserScreen> {

  User user = User();

  @override
  void initState() {
    _getThatUser();
    print(user.username);
  }
  _getThatUser() async {
    print('Getting that user');
    user = await getUser();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('The Yard Users'),
      ),
      body: Container(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: EdgeInsets.only(left: 30.0),
              child: Text(
                'Username: ${user.username}',
                style: TextStyle(
                  fontSize: 24.0,
                ),
              ),
            ),
            // Logout button
            Padding(
              padding: EdgeInsets.fromLTRB(34.0, 20.0, 0.0, 0.0),
              child: Container(
                  width: MediaQuery.of(context).size.width * 0.85,
                  height: MediaQuery.of(context).size.width * 0.16,
                  child: LogoutButton()
              ),
            ),
          ],
        ),
      ),
    );
  }
}
class UserScreen扩展StatefulWidget{
@凌驾
_UserScreenState createState()=>\u UserScreenState();
}
类_UserScreenState扩展状态{
User=User();
@凌驾
void initState(){
_gethatuser();
打印(user.username);
}
_getHatUser()异步{
打印(“获取该用户”);
user=wait getUser();
}
@凌驾
小部件构建(构建上下文){
返回脚手架(
appBar:appBar(
标题:文本(“场地使用者”),
),
主体:容器(
子:列(
mainAxisAlignment:mainAxisAlignment.center,
crossAxisAlignment:crossAxisAlignment.center,
儿童:[
填充物(
填充:仅限边缘设置(左:30.0),
子:文本(
'用户名:${user.Username}',
样式:TextStyle(
字体大小:24.0,
),
),
),
//注销按钮
填充物(
填充:来自LTRB(34.0,20.0,0.0,0.0)的边缘设置,
子:容器(
宽度:MediaQuery.of(context).size.width*0.85,
高度:MediaQuery.of(上下文).size.width*0.16,
子项:注销按钮()
),
),
],
),
),
);
}
}

新屏幕似乎是在数据分配给用户变量之前加载的。我认为使用await命令的全部意义在于这样就不会发生这种情况。显然,我还有很多东西要学,任何帮助都将不胜感激。

这是因为在呈现
文本
小部件之前,您的
未来
尚未完成

您可以通过以下方式进行修复:

  • 如果
    用户名
    ,则显示进度指示器;如果用户名不为
    ,则显示
    用户名
  • 使用
    FutureBuilder
    小部件:
  • class UserScreen扩展StatefulWidget{
    @凌驾
    _UserScreenState createState()=>\u UserScreenState();
    }
    类_UserScreenState扩展状态{
    未来用户;
    @凌驾
    void initState(){
    super.initState();
    futureUser=getUser();
    }
    @凌驾
    小部件构建(构建上下文){
    返回脚手架(
    appBar:appBar(
    标题:文本(“场地使用者”),
    ),
    主体:容器(
    子级:FutureBuilder(//使用FutureBuilder小部件
    future:futureUser,//分配未来
    生成器:(上下文,快照){
    if(snapshot.hasData){
    返回列(
    //显示您的布局,如果未来完成
    mainAxisAlignment:mainAxisAlignment.center,
    crossAxisAlignment:crossAxisAlignment.center,
    儿童:[
    填充物(
    填充:仅限边缘设置(左:30.0),
    子:文本(
    'Username:${snapshot.data.Username}',//从快照获取用户名
    样式:TextStyle(
    字体大小:24.0,
    ),
    ),
    ),
    //注销按钮
    填充物(
    填充:来自LTRB(34.0,20.0,0.0,0.0)的边缘设置,
    子:容器(
    宽度:MediaQuery.of(context).size.width*0.85,
    高度:MediaQuery.of(上下文).size.width*0.16,
    子项:LogoutButton()),
    ),
    ],
    );
    }否则{
    return CircularProgressIndicator();//在future执行时显示进度指示器
    }
    },
    ),
    ),
    );
    }
    }
    
    编辑:


    future
    不应该在
    build
    方法中调用,为什么

    您可能想看看
    FutureBuilder
    小部件。对于第一个解决方案,必须将
    setState
    添加到
    \u gethatuser
    中。第二,未来应该在
    initState
    中获得,它不应该在build中调用。感谢您指出
    build
    方法中保存的
    未来
    ,编辑了我的答案::-。我觉得我需要使用FutureBuilder的时候做了第二个选择-谢谢很多人都很有魅力。我真的不知道我必须接受答案,再次感谢!
               Padding(
                  padding: EdgeInsets.only(left: 30.0),
                  child: user.username == null
                      ? CircularProgressIndicator() // show an indicator if the username is still null
                      : Text(
                          'Username: ${user.username}',
                          style: TextStyle(
                            fontSize: 24.0,
                          ),
                        ),
                ),
    
    class UserScreen extends StatefulWidget {
      @override
      _UserScreenState createState() => _UserScreenState();
    }
    
    class _UserScreenState extends State<UserScreen> {
    
     Future<User> futureUser;
    
      @override
      void initState() {
        super.initState();
        futureUser = getUser();
      }
    
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          appBar: AppBar(
            title: Text('The Yard Users'),
          ),
          body: Container(
            child: FutureBuilder( // use a future builder widget
              future: futureUser, // assign the future
              builder: (context, snapshot) {
                if (snapshot.hasData) {
                  return Column(
                    // show your layout if future is done
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      Padding(
                        padding: EdgeInsets.only(left: 30.0),
                        child: Text(
                          'Username: ${snapshot.data.username}', // get the username from the snapshot
                          style: TextStyle(
                            fontSize: 24.0,
                          ),
                        ),
                      ),
                      // Logout button
                      Padding(
                        padding: EdgeInsets.fromLTRB(34.0, 20.0, 0.0, 0.0),
                        child: Container(
                            width: MediaQuery.of(context).size.width * 0.85,
                            height: MediaQuery.of(context).size.width * 0.16,
                            child: LogoutButton()),
                      ),
                    ],
                  );
                } else {
                  return CircularProgressIndicator(); // show a progress indicator while future is executing
                }
              },
            ),
          ),
        );
      }
    }