1

I am making a flutter app to interact with SQLite database. As I was implementing the feature to add a record(a row), I wanted to add the row to the database if it follows the constraints, but if there is a DatabaseException raised, show an AlertDialog,

  // the function called inside body of onPressed for a submission button
  Future<void> _submitRecord(
    TableWorkAreaConfiguration configuration,
    DatabaseModel databaseModel,
  ) async {
    try {
     //prepare the row to insert into table using the Map type 
      List<Map<String, Object?>> schema = await databaseModel.querySchema(
        widget.name,
      );
      Map<String, Object?> value = {};
      for (var i = 0; i < schema.length; i++) {
        String attribute = schema[i]['name'].toString();
        print("preparing attribute $attribute");
        value[attribute] = configuration.controllers[i].text;
        configuration.controllers[i].clear();
      }

      print(value);
      // insert into the database
      await (await databaseModel.futureDatabse).insert(widget.name, value);
      configuration.turnOffInsertMode();
    } on DatabaseException catch (e) {
      // sqflite_common_ffi package raise this error when the row is unacceptable
      showDialog(
        context: context,
        builder: (context) {
          return AlertDialog(
            title: Text('Database Error'),
            content: Text(e.toString()),
          );
        },
      );
    }
  }

Above function is defined in the state class for a StatefulWidget. The database calls are inherently asynchronous, so I have to use futures. And showDialog requires context as argument. I made the parenet widget StatefulWidget from StatelessWidget only for this reason, but I don't think it is a good practice to achieve my goal described above, and I get the warning

     └╴  Don't use 'BuildContext's across async gaps.
          Try rewriting the code to not use the 'BuildContext', or guard the use with a 'mounted' check. dart (use_build_context_synchronously) [407, 9]

I tried searching existing questions in stackoverflow, but couldn't find one.

The code is working, but I am looking for a best practice.

1
  • Add if (!mounted) return; after every awaited async operation before using context. Commented yesterday

1 Answer 1

5

use (!context.mounted) before accessing context
Here is the example:

void onButtonTapped(BuildContext context) async {
  await Future.delayed(const Duration(seconds: 1));

  if (!context.mounted) return;
  Navigator.of(context).pop();
}
Sign up to request clarification or add additional context in comments.

3 Comments

Can I know what is the scenario that not checking the mounted property causes problem?
mounted property checks if the widget is still in the Widget Tree or not, accessing the context of a widget without checking if it's still mounted causes an Exception: Looking up a deactivated widget's ancestor is unsafe.
And to elaborate, if your main widget is no longer mounted, you've already moved on, perhaps via navigation, and a pop-up dialog will no longer make sense. So it makes sense to abort this if you're actually not on the widget you thought you were.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.