首页 > 解决方案 > 当获取数据的 Sqlite 数据库获取新数据时,如何更新 FutureBuilder?

问题描述

我正在使用 FutureBuilder 来显示来自 sqlite 数据库的数据。我可以使用也在该页面上的抽屉向该数据库添加数据。当我添加新数据时,我希望 FutureBuilder 自动更新,以便页面将显示刚刚添加到 sqlite 数据库的新数据。我怎么能正确地这样做呢?谢谢!

使用 FutureBuilder 显示数据的页面

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.grey[200],
      appBar: PreferredSize(
        preferredSize: Size.fromHeight(95.0),
        child: AppBar(
          automaticallyImplyLeading: false, // hides leading widget
          flexibleSpace: DataAppBar(),
        ),
      ),
      body: FutureBuilder<dynamic>(
        future: DataDBProvider.dataDB.getData(),
        builder: (context, snapshot) {
          switch (snapshot.connectionState) {
          case ConnectionState.none:
          return Text('none');
          case ConnectionState.waiting:
          return Center(child: CircularProgressIndicator());
          case ConnectionState.active:
          return Text('');
          case ConnectionState.done:
          if (snapshot.hasError) {
          print(
          '${snapshot.error}',
          );
          }
          }
      List data = snapshot.data;
        return ListView.builder(
          itemCount: data.length,
          shrinkWrap: true,
          itemBuilder: (context, index) {
            return Padding(
              padding: EdgeInsets.symmetric(vertical: 1.0, horizontal: 4.0),
              child: Card(
                color: (index % 2 == 0) ? greycolor : Colors.white,
                child: Container(
                    height: 60,
                    padding: EdgeInsets.fromLTRB(0, 20, 0, 0),
                    child: Row(
                      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                      children: <Widget>[
                        Flexible(
                          flex: 3,
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Padding(
                                padding: EdgeInsets.only(left: 4),
                                child: Text(data[index].date,
                                    style: TextStyle(fontSize: 14),
                                    textAlign: TextAlign.left),
                              ),
                            ],
                          ),
                        ),
                        Expanded(
                          flex: 5,
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: [
                              Padding(
                                  padding: EdgeInsets.only(),
                                  child: Row(
                                    mainAxisAlignment: MainAxisAlignment.center,
                                    children: [
                                      Text(data[index].title,
                                          style: TextStyle(
                                              fontSize: 15,
                                              fontWeight: FontWeight.bold,
                                              color: Colors.black,
                                              fontFamily: 'Montserrat'),
                                          textAlign: TextAlign.center)
                                    ],
                                  )),
                            ],
                          ),),
                        Expanded(
                          flex: 3,
                          child: Column(
                            crossAxisAlignment: CrossAxisAlignment.end,
                            children: [
                                    Text('\$${data[index].amount}',
                                    style: TextStyle(fontSize: 17,
                                    color: Colors.black),
                                    textAlign: TextAlign.right),
                            ],
                          ),
                        ),
                      ],
                    )),
              ),
            );
          },
        );
        }
    ));
  }

标签: sqliteflutter

解决方案


你可以在下面复制粘贴运行完整代码
来实现自动更新,这样页面就会显示新的数据
。这种情况下,你可以使用包https://pub.dev/packages/sqlbrite并且StreamBuilder
sqlbrite是 Streaming sqfliteBriteDatabase.createQuery方法类似Database.query。听返回的Stream<Query>,它将立即通知Query运行。
并且页面会自动显示新的数据
代码片段

class AppDb {
  ...
  final _dbFuture = _open().then((db) => BriteDatabase(db));

  Stream<List<Item>> getAllItems() async* {
    final db = await _dbFuture;
    yield* db
        .createQuery(_tableItems, orderBy: 'createdAt DESC')
        .mapToList((json) => Item.fromJson(json));
  }

  Future<bool> insert(Item item) async {
    final db = await _dbFuture;
    final id = await db.insert(
      _tableItems,
      item.toJson(),
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
    return id != -1;
  }

  Future<bool> remove(Item item) async {
  ...
  }

  Future<bool> update(Item item) async {
  ...
  }
}  

...
StreamBuilder<List<Item>>(
          stream: AppDb.getInstance().getAllItems(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) {
              return Center(
                child: CircularProgressIndicator(),
              );
            }

            final items = snapshot.data;

            return ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                final item = items[index];

工作演示

在此处输入图像描述

完整代码

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqlbrite/sqlbrite.dart';
import 'dart:math';

const _tableItems = 'items';

Future<Database> _open() async {
  final directory = await getApplicationDocumentsDirectory();
  final path = join(directory.path, 'example.db');
  return await openDatabase(
    path,
    version: 1,
    onCreate: (Database db, int version) async {
      await db.execute(
        '''
          CREATE TABLE $_tableItems( 
              id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, 
              content TEXT NOT NULL,
              createdAt TEXT NOT NULL
          )
        ''',
      );

      final batch = db.batch();
      for (int i = 0; i < 10; i++) {
        batch.insert(
          _tableItems,
          Item(
            null,
            contents.random(),
            DateTime.now(),
          ).toJson(),
        );
      }
      final list = await batch.commit(
        continueOnError: true,
        noResult: false,
      );
      print('Batch result: $list');
    },
  );
}

class AppDb {
  static AppDb _singleton;

  AppDb._();

  factory AppDb.getInstance() => _singleton ??= AppDb._();

  final _dbFuture = _open().then((db) => BriteDatabase(db));

  Stream<List<Item>> getAllItems() async* {
    final db = await _dbFuture;
    yield* db
        .createQuery(_tableItems, orderBy: 'createdAt DESC')
        .mapToList((json) => Item.fromJson(json));
  }

  Future<bool> insert(Item item) async {
    final db = await _dbFuture;
    final id = await db.insert(
      _tableItems,
      item.toJson(),
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
    return id != -1;
  }

  Future<bool> remove(Item item) async {
    final db = await _dbFuture;
    final rows = await db.delete(
      _tableItems,
      where: 'id = ?',
      whereArgs: [item.id],
    );
    return rows > 0;
  }

  Future<bool> update(Item item) async {
    final db = await _dbFuture;
    final rows = await db.update(
      _tableItems,
      item.toJson(),
      where: 'id = ?',
      whereArgs: [item.id],
      conflictAlgorithm: ConflictAlgorithm.replace,
    );
    return rows > 0;
  }
}

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData.dark(),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final _dateFormatter = DateFormat.Hms().add_yMMMd();

  MyHomePage({Key key}) : super(key: key);

  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('sqlbrite example'),
      ),
      body: Container(
        constraints: BoxConstraints.expand(),
        child: StreamBuilder<List<Item>>(
          stream: AppDb.getInstance().getAllItems(),
          builder: (context, snapshot) {
            if (!snapshot.hasData) {
              return Center(
                child: CircularProgressIndicator(),
              );
            }

            final items = snapshot.data;

            return ListView.builder(
              itemCount: items.length,
              itemBuilder: (context, index) {
                final item = items[index];

                return ListTile(
                  title: Text(item.content),
                  subtitle:
                      Text('Created: ${_dateFormatter.format(item.createdAt)}'),
                  trailing: Row(
                    mainAxisSize: MainAxisSize.min,
                    children: [
                      IconButton(
                        icon: Icon(Icons.remove_circle),
                        onPressed: () => _remove(item),
                      ),
                      IconButton(
                        icon: Icon(Icons.edit),
                        onPressed: () => _update(item),
                      ),
                    ],
                  ),
                );
              },
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.add),
        onPressed: _add,
      ),
    );
  }

  void _add() async {
    final item = Item(
      null,
      contents.random(),
      DateTime.now(),
    );
    final success = await AppDb.getInstance().insert(item);
    print('Add: $success');
  }

  void _remove(Item item) async {
    final success = await AppDb.getInstance().remove(item);
    print('Remove: $success');
  }

  void _update(Item item) async {
    final success = await AppDb.getInstance().update(
      item.copyWith(
        contents.random(),
      ),
    );
    print('Update: $success');
  }
}

const contents = [
  'Aaren',
  'Aarika',
  'Abagael',
  'Abagail',
  'Abbe',
  'Abbey',
  'Abbi',
  'Abbie',
  'Abby',
  'Abbye',
  'Abigael',
  'Abigail',
  'Abigale',
  'Abra',
  'Ada',
  'Adah',
  'Adaline',
  'Adan',
  'Adara',
  'Adda',
  'Addi',
  'Addia',
  'Addie',
  'Addy',
  'Adel',
  'Adela',
  'Adelaida',
  'Adelaide',
  'Adele',
  'Adelheid',
  'Adelice',
  'Adelina',
  'Adelind',
  'Adeline',
  'Adella',
  'Adelle',
  'Adena',
  'Adey',
  'Adi',
  'Adiana',
  'Adina',
  'Adora',
  'Adore',
  'Adoree',
  'Adorne',
  'Adrea',
  'Adria',
  'Adriaens',
  'Adrian',
  'Adriana',
  'Adriane',
  'Adrianna',
  'Adrianne',
  'Adriena',
  'Adrienne',
  'Aeriel',
  'Aeriela',
  'Aeriell',
  'Afton',
  'Ag',
  'Agace',
  'Agata',
  'Agatha',
  'Agathe',
  'Aggi',
  'Aggie',
  'Aggy',
  'Agna',
  'Agnella',
  'Agnes',
  'Agnes',
];

extension RandomElementExtension<T> on List<T> {
  T random() {
    final index = Random().nextInt(length);
    return this[index];
  }
}

class Item {
  final int id;
  final String content;
  final DateTime createdAt;

  const Item(
    this.id,
    this.content,
    this.createdAt,
  );

  factory Item.fromJson(Map<String, dynamic> json) {
    return Item(
      json['id'],
      json['content'],
      DateTime.parse(json['createdAt']),
    );
  }

  Map<String, dynamic> toJson() {
    return {
      if (id != null) 'id': id,
      'content': content,
      'createdAt': createdAt.toIso8601String(),
    };
  }

  Item copyWith(String content) => Item(id, content, createdAt);

  @override
  bool operator ==(Object other) =>
      identical(this, other) ||
      other is Item &&
          runtimeType == other.runtimeType &&
          id == other.id &&
          content == other.content &&
          createdAt == other.createdAt;

  @override
  int get hashCode => id.hashCode ^ content.hashCode ^ createdAt.hashCode;

  @override
  String toString() =>
      'Item{id: $id, content: $content, createdAt: $createdAt}';
}

推荐阅读