22
votes

I have a flutter application where I am using the SQFLITE plugin to fetch data from SQLite DB. Here I am facing a weird problem. As per my understanding, we use either async/await or then() function for async programming. Here I have a db.query() method which is conducting some SQL queries to fetch data from the DB. After this function fetches the data, we do some further processing in the .then() function. However, in this approach, I was facing some issues. From where I am calling this getExpensesByFundId(int fundId)function, it doesn't seem to fetch the data properly. It's supposed to return Future> object which will be then converted to List when the data is available. But when I call it doesn't work.

However, I just did some experimentation with it and added "await" keyword in front of the db.query() function and somehow it just started to work fine. Can you explain why adding the await keyword is solving this issue? I thought when using .then() function, we don't need to use the await keyword.

Here are my codes:

Future<List<Expense>> getExpensesByFundId(int fundId) async {
    Database db = await database;

    List<Expense> expenseList = List();

   // The await in the below line is what I'm talking about

    await db.query(expTable,where: '$expTable.$expFundId = $fundId')
        .then((List<Map<String,dynamic>> expList){
      expList.forEach((Map<String, dynamic> expMap){
        expenseList.add(Expense.fromMap(expMap));
      });
    });
    return expenseList;
  }
3

3 Answers

54
votes

In simple words:

await is meant to interrupt the process flow until the async method has finished. then however does not interrupt the process flow (meaning the next instructions will be executed) but enables you to run code when the async method is finished.

In your example, you cannot achieve what you want when you use then because the code is not 'waiting' and the return statement is processed and thus returns an empty list.

When you add the await, you explicitly say: 'don't go further until my Future method is completed (namely the then part).

You could write your code as follows to achieve the same result using only await:

Future<List<Expense>> getExpensesByFundId(int fundId) async {
    Database db = await database;

    List<Expense> expenseList = List();

    List<Map<String,dynamic>> expList = await db.query(expTable,where: '$expTable.$expFundId = $fundId');
    expList.forEach((Map<String, dynamic> expMap) {
        expenseList.add(Expense.fromMap(expMap));
    });

    return expenseList;
}

You could also choose to use only the then part, but you need to ensure that you call getExpensesByFundId properly afterwards:

Future<List<Expense>> getExpensesByFundId(int fundId) async {
    Database db = await database;

    List<Expense> expenseList = List();
    
    return db.query(expTable,where: '$expTable.$expFundId = $fundId')
        .then((List<Map<String,dynamic>> expList){
      expList.forEach((Map<String, dynamic> expMap){
        expenseList.add(Expense.fromMap(expMap));
      });
    });
}

// call either with an await
List<Expense> list = await getExpensesByFundId(1);
// or with a then (knowing that this will not interrupt the process flow and process the next instruction
getExpensesByFundId(1).then((List<Expense> l) { /*...*/ });
2
votes

Adding to the above answers.

Flutter Application is said to be a step by step execution of code, but it's not like that. There are a lot of events going to be triggered in the lifecycle of applications like Click Event, Timers, and all. There must be some code that should be running in the background thread.

How background work execute:

So there are two Queues

  1. Microtask Queue
  2. Event Queue

Microtask Queue runs the code which not supposed to be run by any event(click, timer, etc). It can contain both sync and async work.

Event Queue runs when any external click event occurs in the application like Click event, then that block execution done inside the event loop.

The below diagram will explain in detail how execution will proceed.

enter image description here

Note: At any given point of application development Microtask queue will run then only Event Queue will be able to run.

1
votes

When making class use async for using await its simple logic to make a wait state in your function until your data is retrieve to show.

Example: 1) Its like when you follow click button 2) Data first store in database than Future function use to retrieve data 3) Move that data into variable and than show in screen 4) Variable show like increment in your following/profile.

And then is use one by one step of code, store data in variable and then move to next.

Example: If I click in follow button until data store in variable it continuously retrieve some data to store and not allow next function to run, and if one task is complete than move to another.

Same as your question i was also doing experiment in social media flutter app and this is my understanding. I hope this would help.