Home > front end >  Flutter - How to fix `Instance of 'Future<int>'` when querying SQLite database
Flutter - How to fix `Instance of 'Future<int>'` when querying SQLite database

Time:09-23

Since I want to test foreign key features with SQLite, I am trying to make a simple app.
The app should display inventory information like this:

I made two tables on the SQLite database and added records directly by querying on Android Studio's Database Inspector.

items table

prices table

I tried to get each item's price by querying in the app, but Instance of 'Future<int>' displayed. How can I display item prices correctly?

Main code

class SqliteForeignKeyScreen extends StatefulWidget {
  const SqliteForeignKeyScreen({
    Key? key,
  }) : super(key: key);

  @override
  State<SqliteForeignKeyScreen> createState() => _SqliteForeignKeyScreenState();
}

class _SqliteForeignKeyScreenState extends State<SqliteForeignKeyScreen> {
  Future<List<Item>>? _itemsList;

  void _updateItemsList() {
    setState(() {
      _itemsList = DatabaseHelper.instance.getAllItemsList();
    });
  }

  @override
  void initState() {
    super.initState();
    _updateItemsList();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Items'),
      ),
      body: FutureBuilder(
        future: _itemsList,
        builder: (BuildContext context, AsyncSnapshot snapshot) {
          if (snapshot.hasError) {
            Text('ERROR: ${snapshot.error}');
          }

          if (snapshot.hasData == false) {
            return const CircularProgressIndicator();
          }

          if (snapshot.data.length == null || snapshot.data.length == 0) {
            return const Text('no items');
          }

          return ListView.builder(
              itemCount: snapshot.data.length,
              itemBuilder: (_, index) {
                return _buildItemCards(snapshot.data[index]);
              });
        },
      ),
    );
  }

  _buildItemCards(Item item) {
    var price = DatabaseHelper.instance.getItemPrice(item.id!);
    print('item: ${item.name}, price: ${price}G');

    return Card(
      child: ListTile(
        title: Text(item.name),
        subtitle: Text('${price}G'),
      ),
    );
  }
}

database_helper.dart

class DatabaseHelper {
  static final DatabaseHelper instance = DatabaseHelper._instance();
  static Database? _db;

  DatabaseHelper._instance();

  Future<Database?> get db async {
    _db ??= await _initDb();
    return _db;
  }

  void _configureDb(Database db) async {
    await db.execute('PRAGMA foreign_keys = ON;');
  }

  void _createDb(Database db, int version) async {
    await db.execute('CREATE TABLE items('
        'id INTEGER PRIMARY KEY AUTOINCREMENT,'
        'name TEXT'
        ');');
    await db.execute('CREATE TABLE prices('
        'id INTEGER PRIMARY KEY AUTOINCREMENT,'
        'item_id INTEGER,'
        'price INTEGER,'
        'FOREIGN KEY(item_id) REFERENCES items(id)'
        ');');
  }

  Future<Database> _initDb() async {
    var databasePath = await getDatabasesPath();
    String path = p.join(databasePath, 'inventory.db');
    final inventoryDb = await openDatabase(path,
        version: 1, onConfigure: _configureDb, onCreate: _createDb);
    return inventoryDb;
  }

  Future<List<Map>> getAllItemsMapList() async {
    Database? db = await this.db;
    final List<Map<String, dynamic>> result = await db!.query('items');
    return result;
  }

  Future<List<Item>> getAllItemsList() async {
    final List<Map> itemsMapList = await getAllItemsMapList();
    final List<Item> itemsList = [];
    for (var itemMap in itemsMapList) {
      itemsList.add(Item.fromMap(itemMap));
    }
    return itemsList;
  }

  Future<int> getItemPrice(int itemId) async {
    final Database? db = await this.db;
    final result =
        await db!.query('prices', where: 'item_id = ?', whereArgs: [itemId]);
    return result[0]['price'] as int;
  }
}

item_model.dart

class Item {
  int? id;
  String name;

  Item({
    required this.name,
  });

  Item.withId({
    this.id,
    required this.name,
  });

  factory Item.fromMap(Map map) {
    return Item.withId(
      id: map['id'],
      name: map['name'],
    );
  }
}

Result of print('item: ${item.name}, price: ${price}G');

item: Apple, price: Instance of 'Future<int>'G
item: Banana, price: Instance of 'Future<int>'G
item: Chocolate, price: Instance of 'Future<int>'G

When I changed _buildItemCards like this (added await and async):

_buildItemCards(Item item) async {
    var price = await DatabaseHelper.instance.getItemPrice(item.id!);
    print('item: ${item.name}, price: ${price}G');

    return Card(
      child: ListTile(
        title: Text(item.name),
        subtitle: Text('${price}G'),
      ),
    );
  }

The print('item: ${item.name}, price: ${price}G'); shows correctly:

item: Apple, price: 2G
item: Banana, price: 1G
item: Chocolate, price: 3G

However, the error type 'Future<dynamic>' is not a subtype of type 'Widget' occurred on the screen.

CodePudding user response:

The getItemPrice is a Future function, so you should await for its result, like this:

var price = await DatabaseHelper.instance.getItemPrice(item.id!);

And also the best way to use async function in build method is using FutureBuilder, so change your _buildItemCards to this:

FutureBuilder<int>(
            future: DatabaseHelper.instance.getItemPrice(item.id!),
            builder: (context, snapshot) {
              switch (snapshot.connectionState) {
                case ConnectionState.waiting:
                  return Text('Loading....');
                default:
                  if (snapshot.hasError) {
                    return Text('Error: ${snapshot.error}');
                  } else {
                    int price = snapshot.data!;

                    return Card(
                      child: ListTile(
                        title: Text(item.name),
                        subtitle: Text('${price}G'),
                      ),
                    );
                  }
              }
            },
          )
  • Related