Home > Mobile >  Flutter async await not functioning in order
Flutter async await not functioning in order

Time:05-20

I am working on a project where I have employees scan items into a bin. I am trying to load the information from the database. I have looked at many different posts and found things similar, but never anything that worked.

I have a list (binListDBList) that I am adding data into, then I want to do stuff with it after. I do get a response and it is the correct data, but I have to do a timed delay instead of await. It is clunky and am wondering what a better solution would be.

I have tried async/await and .then and nothing has worked so far. I know there is a solution, but I have spent a lot of time and haven't gotten anywhere.

I have added in a bunch of print statements for testing.

Starting method:

Future<void> loadBinListFromDB(String empID, String binName) async {
  print("start");
  DatabaseService.binListDBList.clear();
  print("Zero: "   DatabaseService.binListDBList.toString());


  await DatabaseService().getBinList(empID, binName);

  print("test");

  if (DatabaseService.binListDBList.isEmpty) {
    print("No Data");
  } else {
    print("data");
  }
  print("Fifth: "   DatabaseService.binListDBList.toString());

  Future.delayed(new Duration(seconds: 1)).then((value) {
    print("last: "   DatabaseService.binListDBList.toString());
  });

  print(DatabaseService.binListDBList);
  return;
}

DatabaseService class

static List<BinListDB> binListDBList = [];

Future<void> getBinList(String employeeID, String binName) async {
    print(employeeID);

    List<BinListDB> hold = [];
    print("First: $binListDBList");
    binListCollection
        .doc(employeeID)
        .collection(binName)
        .snapshots()
        .forEach((element) {
      for (int i = 0; i < element.docs.length; i  ) {
        hold.add(BinListDB.fromFireStore(element.docs[i]));
      }
      print("Second: $binListDBList");
      binListDBList = hold;
      print("Third: $binListDBList");
    });
    print("Fourth: $binListDBList");
    return;

  }

output:

I/flutter (26448): start
I/flutter (26448): Zero: []
I/flutter (26448): EmployeeID
I/flutter (26448): First: []
I/flutter (26448): Fourth: []
I/flutter (26448): test
I/flutter (26448): No Data
I/flutter (26448): Fifth: []
I/flutter (26448): finish
I/flutter (26448): Second: []
I/flutter (26448): Third: [Instance of 'BinListDB']
I/flutter (26448): last: [Instance of 'BinListDB']

I don't understand why it isn't printing in order.

Any help is very appreciated, and thanks for reading.

CodePudding user response:

You do:

    binListCollection
        .doc(employeeID)
        .collection(binName)
        .snapshots()
        .forEach((element) {
      ...
    });

snapshots() returns a Stream, which is asynchronous. You call Stream.forEach to iterate over each element of the Stream, and Stream.forEach returns a Future to indicate when it's complete, but you neglect to await that Future. The caller of Stream.forEach therefore continues executing immediately, and you see "Fourth" printed (and later "Fifth" and "finished") before Stream.forEach's callback prints "Second" and "Third".

I strongly suggest enabling the unawaited_futures lint to let the analyzer catch such errors.

CodePudding user response:

I haven't checked all the code but, you're using async/await and you're assuming that await means that the code will stop being executed until you'll get the servers response, in order to keep an specific order for each Future you need to work with the command .whenComplete() after every Future statement, otherwise if the server doesn't responds before the future timer ends (if the server takes more than 1 second to respond), the code will still run, when you set .whenComplete() you're telling the code to await for the Future and also that the code that is inside parenthesis can't start until the value has changed. So, right now you have your code like this:

await DatabaseService().getBinList(empID, binName);

When you should have your code like this:

await DatabaseService().getBinList(empID, binName).whenComplete(
  print("test");
  
  if (DatabaseService.binListDBList.isEmpty) {
    print("No Data");
  } else {
    print("data");
  }
  print("Fifth: "   DatabaseService.binListDBList.toString());
  print("last: "   DatabaseService.binListDBList.toString());
  print(DatabaseService.binListDBList);
  return;
);

Same thing for the rest of the code

  • Related