Home > Enterprise >  Flutter - How to complete/await function execution before build method?
Flutter - How to complete/await function execution before build method?

Time:12-17

I am simply trying to set an ID in this function:

      _getLastWorkoutId() async {
    
    try {
      var snapshot = await usersRef
          .doc(currentUser!.uid)
          .collection('workouts')
          .orderBy('workoutDate', descending: true)
          .limit(1)
          .snapshots()
          .first; 
    //The execution moves to build method from here------and then returns
      for (var element in snapshot.docs) {
        workoutId = element.id;
        setState(() {
          _isWorkoutIdSet = true;
        });
      }
      //return snapshot;
    } catch (e) {
      print(e.toString());
    }
    //return null;
  }

I call it in the initState:

    @override
void initState() {
  WidgetsBinding.instance!.addObserver(this);
  super.initState();
  //var snapshot = _getLastWorkoutId();
  _getLastWorkoutId();
}

The problem is, the for loop executes after the build function is called. I don't want that to happen.

CodePudding user response:

You can use FutureBuilder like this:

Future<bool> _value;

@override
void initState() {
  WidgetsBinding.instance!.addObserver(this);
  super.initState();
  _value = _getLastWorkoutId();
}

And in your build method you have:

 FutureBuilder<bool>(
    future: _value,
    builder: (
      BuildContext context,
      AsyncSnapshot<bool> snapshot,
    ) {
      if (snapshot.hasData) {
        if (snapshot.data){
           //update view 
         }else{
           //update view
         }
      }
    }

The method can be like this:

   _getLastWorkoutId() async {
        try {
          var snapshot = await usersRef
              .doc(currentUser!.uid)
              .collection('workouts')
              .orderBy('workoutDate', descending: true)
              .limit(1)
              .snapshots()
              .first; 
          for (var element in snapshot.docs) {
            workoutId = element.id;
            return true;
          }
        } catch (e) {
          print(e.toString());
        }
      }

Here you can find more about FutureBuilder.

CodePudding user response:

I believe this should solve the issue:

First, on build method:

return FutureBuilder(
  future: _getLastWorkoutId(),
  builder: (context, snapshot) {
    if (snapshot.connectionState != ConnectionState.done) return CircularProgressIndicator();
    return Container(); // here goes whatever it is you had before.
  }
);

then on _getLastWorkoutId():

Future<void> _getLastWorkoutId() async {
  ...
}

That way the function returns a future of void instead of void, allowing FutureBuilder to do its thing.

  • Related