Flutter 应用中提供程序与 sqflite 的集成

Posted

技术标签:

【中文标题】Flutter 应用中提供程序与 sqflite 的集成【英文标题】:Provider integration with sqflite in flutter app 【发布时间】:2021-03-04 06:51:56 【问题描述】:

我正在尝试实现提供程序模式,但我正在努力将其与 sqflite 数据库集成。 ChangeNotifier 类从数据库中获取字符串列表,然后用 ListView 显示它。我想问题在于,当 ListView 构建小部件时,ChangeNotifier 类尚未初始化列表,因此应用程序崩溃。我该如何解决这个问题?

class FavouritesProvider with ChangeNotifier 

  List<String> _favourites;

  List<String> get favourites => [..._favourites];

  FavouritesProvider() 
    fetchAndSetFav();
  

  Future<void> fetchAndSetFav() async 
    final data = await DBHelper.instance.getFavourites();
    _favourites = data;
  



@override
  Widget build(BuildContext context) 
    return Scaffold(
      body: ChangeNotifierProvider(
      create: (_) => FavouritesProvider(),
      child: Container (
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.bottomCenter,
            end: Alignment.topCenter,
            colors: [
              Colors.blue[200],
              Colors.blue
            ],
            stops: [0.0,1]
          )
        ),
        child: Consumer<FavouritesProvider>(
          builder: (context, favouritesProvider, child) => ListView.builder (
                itemCount: favouritesProvider.favourites.length,
                itemBuilder: (context, index) 
                  return Container(
                    padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
                    width: double.maxFinite,
                    child: FavouritePositionWidget(key: new Key(index.toString()), streetName: favouritesProvider.favourites[index])
                  );
                ,
          )
        )
      )
      )
    );
  

这是我得到的错误:

The following NoSuchMethodError was thrown building Consumer<FavouritesProvider>(dirty, dependencies: [_InheritedProviderScope<FavouritesProvider>]):
The getter 'iterator' was called on null.
Receiver: null
Tried calling: iterator
Future<List<String>> getFavourites() async 
  // Get a reference to the database.
  Database db = await DBHelper.instance.database;
  List<Map> res = await db.query(table, columns: [columnName]);
  List<String> list = [];
  for (Map i in res)
      var str = i.values.toString();
      str=str.substring(1, str.length-1);
      list.add(str);
  
  return list;
  

【问题讨论】:

【参考方案1】:

在构建之前您需要awaitfetchAndSetFav()

class FavouritesProvider with ChangeNotifier 

  Future isInitCompleted;
  List<String> _favourites;
  List<String> get favourites => [..._favourites];

  FavouritesProvider() 
   isInitCompleted = fetchAndSetFav();
  

  Future<void> fetchAndSetFav() async 
    final data = await DBHelper.instance.getFavourites();
    _favourites = data;
  


还有:

@override
  Widget build(BuildContext context) 
    return Scaffold(
      body: ChangeNotifierProvider(
      create: (_) => FavouritesProvider(),
      child: Container (
        decoration: BoxDecoration(
          gradient: LinearGradient(
            begin: Alignment.bottomCenter,
            end: Alignment.topCenter,
            colors: [
              Colors.blue[200],
              Colors.blue
            ],
            stops: [0.0,1]
          )
        ),
        child: Consumer<FavouritesProvider>(
          builder: (context, favouritesProvider, child) 
              return FutureBuilder(
                       future: favouritesProvider.isInitCompleted,
                       builder: (context, snapshot) 
                         if (snapshot.hasData) 
                         return ListView.builder(
                                  itemCount: favouritesProvider.favourites.length,
                                  itemBuilder: (context, index) 
                                    return Container(
                                             padding: EdgeInsets.fromLTRB(10, 10, 10, 0),
                                             width: double.maxFinite,
                                             child: FavouritePositionWidget(
                                               key: Key(index.toString()),
                                               streetName: favouritesProvider.favourites[index],
                                                     )
                                            );
                                  ,
                                )
                          else 
                             return Center(
                                      child: CircularProgressIndicator(),
                                    );
                         
                       ,
                     ),
          
        )
      )
      )
    );
  
class DBHelper 
  static final _databaseName = "FavDatabase.db";
  static final _databaseVersion = 1;

  static final table = 'favPosition';

  static final columnName = 'street';
  static final columnNot = 'notification';

  DBHelper._privateConstructor();
  static final DBHelper instance = DBHelper._privateConstructor();
  static Database _database;

  Future<Database> get database async 
    if (_database != null) return _database;
    _database = await _initDatabase();
    return _database;
  

  _initDatabase() async 
  Directory documentsDirectory = await getApplicationDocumentsDirectory();
  String path = join(documentsDirectory.path, _databaseName);
  return await openDatabase(path,
      version: _databaseVersion,
      onCreate: _onCreate);

  

  // SQL code to create the database table
  Future _onCreate(Database db, int version) async 
    await db.execute('''
          CREATE TABLE $table (
            $columnName TEXT NOT NULL PRIMARY KEY,
            $columnNot BIT(1) NOT NULL
          )
          ''');
    print("db was created");    
  

  Future<void> insertPos(String street) async 
  
    final Database db = await database;
    final List<Map<String, dynamic>> res = await db.query(table, where: "street = ?", whereArgs: [street]);
    if (!res.isNotEmpty) 
      print("lo deve aggiungere");
      Map<String, dynamic> row = 
        DBHelper.columnName : street,
        DBHelper.columnNot  : 1,
      ;
      await db.insert(table, row);
     else 
      print("gia aggiunt!");
    
  

  //Delete a street from the DB
  Future<void> deletePos(String street) async 
    Database db = await DBHelper.instance.database;
    await db.delete(table, where: 'street = ?', whereArgs: [street]);
  

  //Update the notification boolean 
  Future<void> updateNot(String street, bool value) async 
    // Get a reference to the database.
    Database db = await DBHelper.instance.database;

    Map<String, dynamic> row = 
      DBHelper.columnName : street,
      DBHelper.columnNot  : value?1:0,
    ;
    await db.update(table, row, where: '$DBHelper.columnName = ?', whereArgs: [street]);
  

  //Return a String list of all street's name in the DB
  Future<List<String>> getFavourites() async 
    // Get a reference to the database.
    Database db = await DBHelper.instance.database;

    List<Map> res = await db.query(table, columns: [columnName]);
    List<String> list = [];
    for (Map i in res)
        var str = i.values.toString();
        str=str.substring(1, str.length-1);
        list.add(str);
    
    return list;
  


  Future<bool> getNotification(String street) async 
    // Get a reference to the database.
    Database db = await DBHelper.instance.database;

    List<Map> res = await db.query(table, columns: [columnNot], where: '$DBHelper.columnName = ?', whereArgs: [street]);
    String value = res[0].values.toString();
    value = value.substring(1, 2);
    if (value == "1") 
      return true;
     else if (value == "0") 
      return false;
     else 
      throw FormatException("Value can only be 0 or 1");
     
  


【讨论】:

我该怎么做? 卡在等待 IsInitCompleted 的未来构建器中 DBHelper.instance.getFavourites() 有问题。请显示一些代码。 DBHelper 里面有什么? 对 sqflite 数据库执行操作的函数,但到目前为止它们运行良好

以上是关于Flutter 应用中提供程序与 sqflite 的集成的主要内容,如果未能解决你的问题,请参考以下文章

在 Flutter 中使用 SQFlite 将本地存储的 DB 导出为可读文件

测试 Flutter 本地 sqflite 数据库 onUpgrade 并且应用更新后没有数据显示

如何在flutter中将图像数据保存到sqflite数据库以进行持久化

Flutter ListView 不会更新

在颤振应用程序中坚持与 sqflite 的提供商集成

Flutter sqflite 打开现有数据库