简体   繁体   中英

Retrieving Data From Firestore in time (outside of Widget build(BuildContext context) )

If you would like some context I asked a similar question here . In my flutter app you are able to send emails

  static getEmailCredentials(String email1, String password1) {
    email = email1;
    passw = password1;
  }

  sendMail() async {
    String username = email;//gets email from db 
    String password = passw;//gets password for email from db

    final SmtpServer = gmail(username, password); //fix one day

    final message = Message()
      ..from = Address(username)
      ..recipients.add("xxx@gmail.com")
      ..subject = "From "+name //need name here from db
      ..html = "<h3>" + emailContent.text + "</h3>";

    try {
      final SendReport = await send(message, SmtpServer);
      Fluttertoast.showToast(
        msg: "Message sent! Hang in there!",
        gravity: ToastGravity.CENTER,
      );
    } on MailerException catch (e) {
      e.toString();
      Fluttertoast.showToast(
        msg: "Message failed to send! Try again?",
        gravity: ToastGravity.CENTER,
      );
    }
  }
}

As seen above. I know it's probably not the best to store the email and password but it works (well it would work if the data came in time). So my problem is I'll run this function at the beginning of the app but sometimes it won't load in on time.

UI Code:

class EmergencyReport extends StatelessWidget {
  EmergencyReport();

  static String email;
  static String passw;
  final TextEditingController emailContent = TextEditingController();

  @override
  Widget build(BuildContext context) {
    getEmailCredentialsF();//function that calls to db
    DateTime now = DateTime.now();
    DateTime weekAgo = now.subtract(new Duration(days: 7));
    DateFormat formadate = DateFormat('dd-MM');
    String formatedDate = formadate.format(now); // current date formatted
    String weekAgoForm =
        formadate.format(weekAgo); // date from week ago formatted
    countDocuments();
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        backgroundColor: Colors.blueGrey,
        body: SingleChildScrollView(
          child: Center(
            child: Column(
              children: <Widget>[
                Align(
                  alignment: Alignment.topLeft,
                  child: Container(
                    width: 54,
                    margin: EdgeInsets.only(top: 44),
                    child: FlatButton(
                      onPressed: () {
                        Navigator.of(context).pop();
                      },
                      child: Column(
                        children: <Widget>[Icon(Icons.arrow_back_ios)],
                      ),
                    ),
                  ),
                ),
                Text(
                  "Emergency Report",
                  style: new TextStyle(
                    color: Colors.white,
                    fontSize: MediaQuery.of(context).size.width / 10,
                  ),
                ),
                Card(
                    margin: EdgeInsets.only(top: 30),
                    color: Colors.white,
                    child: Padding(
                      padding: EdgeInsets.all(8.0),
                      child: TextField(
                        controller: emailContent,
                        maxLines: 8,
                        decoration: InputDecoration.collapsed(
                            hintText: "Enter what happened here..."),
                      ),
                    )),
                Container(
                  width: 260,
                  height: 70,
                  padding: EdgeInsets.only(top: 20),
                  child: RaisedButton(
                    shape: RoundedRectangleBorder(
                      borderRadius: BorderRadius.circular(20.0),
                    ),
                    child: Text(
                      "Send",
                      style: new TextStyle(
                        color: Colors.white,
                        fontSize: 38.0,
                      ),
                    ),
                    color: Colors.grey[850],
                    onPressed: () {
                      if (emailContent.text != "") {
                        sendMail();
                        Navigator.of(context).pop();
                      } else {
                        Fluttertoast.showToast(
                          msg: "You need to put a message!",
                          gravity: ToastGravity.CENTER,
                        );
                      }
                    },
                  ),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
void getEmailCredentialsF() {
  print("Attemping to get email!");
  final firestoreInstance = FirebaseFirestore.instance;
  FirebaseAuth auth = FirebaseAuth.instance;
  String uid = auth.currentUser.uid.toString();
  firestoreInstance.collection("SendMailCredentials").doc("w1HsHFRgq7Oc3X9xUEnH").get().then((value) {
    EmergencyReport.getEmailCredentials((value.data()["email"]),(value.data()["password"]));
  });
}

Is there a way to make the code wait for that information to be gathered from the db before running the rest? I've tried await and async and future builders (could have used them wrong I am fairly new to flutter)

Thank you for all the help you give

Pic of UI if it helps UI

yesterday I've answered you this

FutureBuilder<DocumentSnapshot>(
          future: firestoreInstance.collection("Users").doc(uid).get(),
          builder: (_,snap){
          return snap.hasData ? Text(snap.data.data()["firstName"]):CircularProgressIndicator();
        },)

now implement the same like Lets say you have a Object which you keep saperate from UI

class MyDB{
 //...
}

and you need to get document in users collection


class MyDB{
  MyDB();
  Map<String,dynamic> userData;
  
  Future<void> getUser() async {
    userData = //...set
  }
}

and you want to get something else


class MyDB{
  MyDB();
  Map<String,dynamic> userData;
  Map<String,dynamic> someThingElse;

  Future<void> getUser() async {
    userData = //...set
  }
  Future<void> getSomeThingElse() async {
    someThingElse = //...set
  }
}

and you want to wait for all these data to be available before you show anything


class MyDB{
  MyDB();
  Map<String,dynamic> userData;
  Map<String,dynamic> someThingElse;

  Future<void> getUser() async {
    userData = //...set
  }
  Future<void> getSomeThingElse() async {
    someThingElse = //...set
  }
  
  Future getEveryThing() async {
    await getUser();
    await getSomeThingElse();
  }
}

now use that getEverything future in UI


final myDB = MyDB();
build(){
  return FutureBuilder<bool>(
    future: myDB.getEveryThing(),
    builder: (_,snap){
      if(snap.hasData){
        //myDB.userData and myDB.someThingElse will not be null
      }
      //if we are still waiting for the data
      return CircularProgressIndicator();
    },);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM