如何确保在Widget构建之前加载异步函数?

问题描述 投票:0回答:4

我有一个屏幕,其中包含有关用户的一些信息。

在我的构建小部件中,我有这个:

Column
 (
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.start,
    children: <Widget>
    [
    Text('User Points', style: TextStyle(color: Colors.blueAccent)),
    Text('${this.user.points}', style: TextStyle(color: Colors.black, fontWeight: FontWeight.w700, fontSize: 34.0))
    ],
 ),

我有一个功能,每次用户访问它时更新仪表板。

void updateDashboard() async{
    SharedPreferences prefs = await SharedPreferences.getInstance();
    var api_key = prefs.getString('api_key');
    var userID = prefs.getInt('userID');

    var res = await http.post(('http://myApp.com/getDashboardPreferences/'+userID.toString() + '/' + api_key),
        headers: {
          "Accept": "application/json",
          "content-type": "application/json"
        });

    this.user = User.fromJson(json.decode(res.body));

    setState(() {
      if (res.statusCode == 200) { 
        this.user.setPoints(this.user.points);
      } else {
        print("Something is wrong");
      }
    });

  }

在initstate中我调用该函数:

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

这有效,但是,我得到${this.user.points}null几秒钟(我得到警告屏幕)然后它被加载,一切都很好。我想这是因为我的功能是async ...但是我怎么能保证在渲染updateDashboard()之前调用这个Widget build()

dart flutter
4个回答
1
投票

如果你不想使用FutureBuilder那么你可以做类似的事情

if(done)
    Column(  /* whatever */ )
else
    Center(child: CircularProgressIndicator())
void updateDashboard() async{
    /* whatever */

     if (res.statusCode == 200) { 
        setState(() {
           this.user.setPoints(this.user.points);

           done = true;

      });          
 }

@override
  void initState() {
    /* whatever */
    done = false;
  }

1
投票

好吧,异步意味着数据可能需要一些时间来加载,并被转移到另一个线程加载。可以有多种非阻塞方式来执行此操作:

  1. user对象提供默认值,因此在async方法完成时,您将显示代理/默认值,setState()确保在加载时显示新值。
  2. 这种方法要求你有条件地加载小部件,即当有数据加载Text时加载Container()小部件。

第二种方法的示例:

this.user!=null?Text('${this.user.points}'):Container()

这样,您不需要显示窗口小部件,直到值加载。这两种方法都可以使用,并且根据您的使用情况,您可以选择可以应用的方法。


0
投票

您可以在返回小部件之前放置该函数。


0
投票

你可以制作一个加载变量,如bool _loading然后你开始loadingasync函数,你可以setState加载到真setState loading async函数停止加载像这样。

void updateDashboard() async{

    setState(() {
      _loading = true;
    });

    SharedPreferences prefs = await SharedPreferences.getInstance();
    var api_key = prefs.getString('api_key');
    var userID = prefs.getInt('userID');

    var res = await http.post(('http://myApp.com/getDashboardPreferences/'+userID.toString() + '/' + api_key),
        headers: {
          "Accept": "application/json",
          "content-type": "application/json"
        });

    this.user = User.fromJson(json.decode(res.body));

    setState(() {
      if (res.statusCode == 200) { 
        this.user.setPoints(this.user.points);
      } else {
        print("Something is wrong");
      }

      _loading = false; //Set Loading to false
    });



}

然后在您的小部件构建中,检查加载是否为真,并显示这样的进度指示器。

body: _loading
? Center(
   child: CircularProgressIndicator( //Show a Circular Progress indicator
     valueColor: new AlwaysStoppedAnimation<Color>(Colors.cyan),
    ),
  )
:Column(//Show your Dashboard)

我希望它有所帮助

© www.soinside.com 2019 - 2024. All rights reserved.