0

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.

1 Answer 1

2

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'),
                      ),
                    );
                  }
              }
            },
          )
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for your answer. I added await to it and async to _buildItemCards, but an error occurred: type 'Future<dynamic>' is not a subtype of type 'Widget'
I updated my answer, check it out, @extxuser

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.