如何确保在Widget构建之前已加载异步功能?

时间:2019-05-01 16:17:38

标签: dart flutter

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

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

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");
      }
    });

  }

在初始化状态下,我调用该函数:

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

这有效,但是,我发现${this.user.points}null了几秒钟(我得到了警告屏幕),然后加载了它,一切正常。我猜是因为我的函数是async ...但是我如何确保在渲染updateDashboard()之前调用此Widget build()

4 个答案:

答案 0 :(得分:1)

好吧,异步意味着数据可能需要花费一些时间才能加载,并且会移交给另一个线程进行加载。可以有多种非阻塞方式来做到这一点:

  1. user对象提供默认值,因此在异步方法完成时,您将显示代理/默认值,并且setState()确保在加载时显示新值。

  2. 此方法要求您有条件地加载小部件,即在有数据时加载Text小部件,否则加载Container()

第二种方法的示例:

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

这样,您无需在加载值之前显示小部件。两种方法都有效,并且取决于您的用例,您可以选择可以应用的方法。

答案 1 :(得分: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;
  }

答案 2 :(得分:0)

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

答案 3 :(得分:0)

您可以创建一个bool _loading之类的加载变量,然后在任何开始loading的地方async函数中,可以setState加载为true,然后setStateloading函数停止像这样加载时,{1}}为false。

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
    });



}

我希望对您有帮助