在执行任何操作之前如何等待异步功能完成?

时间:2019-05-31 10:36:57

标签: flutter

我正在使用登录API登录到我的应用程序,并且从登录API收到的响应中,我想调用另一个将填充主页上数据的API。

但是,当我尝试进行第二次API调用然后移至主页时。在API完成之前,它将移至第二页并提供空值。 (第二次API调用工作正常,并在一段时间后提供了请求数据)

我该如何解决?谢谢。

我的登录页面

import .....

class Login extends StatefulWidget{

  final void Function(UserCredentials) onSignedIn;

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

class _LoginState extends State<Login> {

  var response;

  //To save data from  FIRST API to shared Pref
  Future<bool> saveNamedPreference(String ID, String authid) async {

    SharedPreferences prefs = await SharedPreferences.getInstance();

    prefs.setString("ID", ID );
    prefs.setString("authID", authid );

    return await prefs.setBool("iDExist", true);
  }


  //
  //To save data from  SECOND API to shared Pref
  Future<bool> saveUserPreference(String name, String role) async {

    SharedPreferences prefs = await SharedPreferences.getInstance();

    prefs.setString("name", name);
    prefs.setString("role", role );

    return await prefs.setBool("UserExists", true);
  }


  @override
  Widget build(BuildContext context){

    //SECOND API CALL 
    Future<int> saveUserDetails(String userID, String authID) async{

      getUser(userID, authID).then((value){

        final json = value;
        if(json!="Error"){
          User user = userFromJson(json);
          saveUserPreference(user.username, user.role);
          print('set the other values too ');
          return 1;
        }
        else{
          print('dint get proper json data ');
          return 0;
        }
      });

    }

    //LOGIN API 
    Future<Map<String, dynamic>> getData() async {
      var client = http.Client();


      var response = await client
          .post(
          Uri.encodeFull(
              '{url}'),
          body:
        {"email":"$username","password":"$password"}

      ).whenComplete(
          client.close);

      var res = json.decode(response.body);

      if(response.statusCode <200 || response.statusCode > 400){
        print("Error");
         throwError();
      }
      if(response.statusCode == 200 ){

        saveNamedPreference(res["userId"], res["id"]);;
        UserCredentials uc = userCredentialsFromJson(response.body);

//Using then so that it shifts to Home only after func completion however its not happening 
        saveUserDetails(uc.userId, uc.id).then((value){
          widget.onSignedIn(uc); //gives call back to root page to move to HOME 
        });
      }

      if (!mounted)
        return {'success': false};

      return json.decode(response.body);
    }
;

    Stack stack = Stack(
      ...... );

    return Scaffold(
        resizeToAvoidBottomPadding: false,
      body: stack
    );
  }
}

在我的主页的init方法中,我正在访问Shared Pref的值(使用相同的async then方法),然后使用setState更新该值,但该值仍为空值。

1 个答案:

答案 0 :(得分:0)

首先,将所有带有api调用的方法移至build方法之外。

问题可能出在这里: saveNamedPreference(res["userId"], res["id"]);

您不会等到此方法返回。 当您使用异步方法并要等待响应时,需要使用await。

我认为这段代码看起来要好得多...

import .....

class Login extends StatefulWidget {

  final void Function(UserCredentials) onSignedIn;

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

class _LoginState extends State<Login> {
  var response;

  //To save data from  FIRST API to shared Pref
  Future<bool> saveNamedPreference(String ID, String authid) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    prefs.setString("ID", ID);
    prefs.setString("authID", authid);

    return await prefs.setBool("iDExist", true);
  }

  //To save data from  SECOND API to shared Pref
  Future<bool> saveUserPreference(String name, String role) async {
    SharedPreferences prefs = await SharedPreferences.getInstance();

    prefs.setString("name", name);
    prefs.setString("role", role);

    return await prefs.setBool("UserExists", true);
  }

  //SECOND API CALL 
  Future<int> saveUserDetails(String userID, String authID) async {
    final json = await getUser(userID, authID);

    if (json != "Error") {
      User user = userFromJson(json);
      saveUserPreference(user.username, user.role);
      print('set the other values too ');
      return 1;
    } else {
      print('dint get proper json data ');
      return 0;
    }
  }

  //LOGIN API 
  Future<Map<String, dynamic>> getData() async {
    var client = http.Client();

    var response = await client
        .post(
        Uri.encodeFull('{url}'),
        body: {"email": "$username", "password": "$password"}
    );

    var res = json.decode(response.body);

    if (response.statusCode < 200 || response.statusCode > 400) {
      print("Error");
      throwError();
    }

    if (response.statusCode == 200) {
      await saveNamedPreference(res["userId"], res["id"]);
      UserCredentials uc = userCredentialsFromJson(response.body);

      //Using then so that it shifts to Home only after func completion however its not happening 
      await saveUserDetails(uc.userId, uc.id);
      widget.onSignedIn(uc); //gives call back to root page to move to HOME
    }

    if (!mounted) {
      return {'success': false};
    }

    return json.decode(response.body);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        resizeToAvoidBottomPadding: false,
        body: _buildStack(),
    );
  }

  Widget _buildStack(){
    return Stack(
      ......
    );
  }
}