Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I wait for an async function to finish executing before rendering a widget in Flutter

On my main.dart file, I want to check if a user is logged so as to direct him to the appropriate screen. I am using SharedPrefence to store user detail from Firebase. How do I tell my function to wait until my SharedPreference async function finishes executing before it can render the appropriate widget.

Below is my code

  Widget _gotoHomeScreen() {
  AuthService.getuserPrefEmail().then((email) {
  print(email);
  AuthService.email = email;
  if (email == null) {
    return LoginScreen();
  } else {
    AuthService.uid = email;
    return HomeMenuScreen();
  }
});

}

like image 762
Ilo Calistus Avatar asked Nov 06 '19 11:11

Ilo Calistus


2 Answers

You don't have to wait for the build, you should build something, to show to the user that the app is loading something (or a blank screen), and then rebuild when the funcion ends.

You could have a Widget variable that is set to a default when you create the widget, say with a CircularProgressIndicator, then change it with setState, something like this:

class YourWidgetState extends State<YourWidget> {
  Widget _body = CircularProgressIndicator();  // Default Body

  @override
  void initState(){
    _gotoHomeScreen();
  }

  @override
  Widget build(BuildContext context){
    return _body;
  }

  Widget _gotoHomeScreen() {
    AuthService.getuserPrefEmail().then((email){
      AuthService.email = email;
      if (email == null) {
        setState(() => _body = LoginScreen());
      } else {
        AuthService.uid = email;
        setState(() => _body = HomeMenuScreen());
      }
    });
  }
}

Another way would be to use a variable to inform you about the loading situation, like bool finishedLoading, and call setState to change the value when it's done, using the email variable you set to know when the user is logged in, and do a conditional build, like this:

bool loading = true;

@override
Widget build(BuildContext context){
  if(loading) return CircularProgressIndicator();

  if(AuthService.email == null)
    return LoginScreen();
  else
    return HomeMenuScreen();
}

Widget _gotoHomeScreen() {
  AuthService.getuserPrefEmail().then((email){
    AuthService.email = email;
    if (email != null) {
     AuthService.uid = email;
    }
    setState((){ loading = false; });
  });
}
like image 135
George Avatar answered Oct 13 '22 10:10

George


Use a simple FutureBuilder!

https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html

FutureBuilder<Email>(
future: AuthService.getuserPrefEmail(),
 builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
  switch (snapshot.connectionState) {
    case ConnectionState.active:
    case ConnectionState.waiting:
     return CircularProgressIndicator();
    case ConnectionState.done:
     if (snapshot.hasError) {
       return Text('Error: ${snapshot.error}');
      }
     .... here route to your screen or set it how you want
  }
 },
)
like image 42
Marvin Böddeker Avatar answered Oct 13 '22 11:10

Marvin Böddeker