Flutter 初始化的数据库仍然返回null[flatter,sqflite]

Flutter 初始化的数据库仍然返回null[flatter,sqflite],flutter,dart,sqflite,Flutter,Dart,Sqflite,我正在尝试使用sqflite库对Flutter执行CRUD操作。在线资源指出了一系列解决这一问题的方法。以下是我的实现: class SqlManager { static const String tname = 'table1'; static const String dname = 'database.db'; Future<Database> db; initDB() async { Directory path = await getApplicatio

我正在尝试使用sqflite库对Flutter执行CRUD操作。在线资源指出了一系列解决这一问题的方法。以下是我的实现:

class SqlManager { 
 static const String tname = 'table1';
 static const String dname = 'database.db';
 Future<Database> db;

 initDB() async {
   Directory path = await getApplicationDocumentsDirectory();
   db = openDatabase(join(path.path, dname), version: 1, onCreate: (db, version) {
     return db.execute(
         'CREATE TABLE $tname (id INTEGER PRIMARY KEY, name TEXT, type TEXT, time1 INTEGER, time2 INTEGER, imp INTEGER, urg INTEGER)');
   });
 }

 Future<void> writing(Task task) async {
   print("called");
   final Database DB = await db;
   await DB.insert(
     tname,
     task.toMap(),
     conflictAlgorithm: ConflictAlgorithm.replace,
   );
   print("Execution completed");
 }

 Future<List<Task>> reading() async {
   Database DB = await db;
   List<Map<String, dynamic>> maps = await DB.query(tname);
   return List.generate(maps.length, (i) {
     return Task.fromMap(maps[i]);
   });
 }
} 
类SqlManager{
静态常量字符串tname='table1';
静态常量字符串dname='database.db';
未来数据库;
initDB()异步{
目录路径=等待getApplicationDocumentsDirectory();
db=openDatabase(join(path.path,dname),版本:1,onCreate:(db,版本){
返回db.execute(
'创建表$tname(id整型主键、名称文本、类型文本、time1整型、time2整型、imp整型、urg整型)';
});
}
未来写入(任务)异步{
印刷品(“被称为”);
最终数据库DB=等待数据库;
等待DB.insert(
名称,
task.toMap(),
conflictAlgorithm:conflictAlgorithm.replace,
);
打印(“执行完成”);
}
Future reading()异步{
数据库DB=等待DB;
列表映射=等待DB.query(tname);
返回列表。生成(maps.length,(i){
返回Task.fromMap(maps[i]);
});
}
} 
每当我试图调用这些函数中的任何一个时,我都会遇到NoSuchMethodError,它是由其中一个函数中的变量“DB”引发的。感谢您的帮助,谢谢

每当我试图调用这些函数中的任何一个时,我都会遇到NoSuchMethodError,它是由其中一个函数中的变量“DB”引发的。感谢您的帮助,谢谢

这是因为您尚未通过调用
initDB()
初始化数据库。因此,在使用数据库调用方法之前先调用它。但最后,您将为每个调用重新创建每个实例

更好的方法是为数据库创建一个单例。将您的
SqlManager
修改为如下内容:

class SqlManager { 
  static const String tname = 'table1';
  static const String dname = 'database.db';
  // Future<Database> db;

  // Make a singleton class
  SqlManager._privateConstructor();

  static final SqlManager instance = SqlManager._privateConstructor();

  // Use a single reference to the db.
  static Database _db;

  // Use this getter to use the database.
  Future<Database> get database async {
    if (_db != null) return _database;
    // Instantiate db the first time it is accessed
    _db = await _initDB();
    return _db;
  }

  // Init the database for the first time.
  _initDB() async {
    Directory path = await getApplicationDocumentsDirectory();
    return await openDatabase(join(path.path, dname), version: 1, onCreate: (db, version) {
     return db.execute(
         'CREATE TABLE $tname (id INTEGER PRIMARY KEY, name TEXT, type TEXT, time1 INTEGER, time2 INTEGER, imp INTEGER, urg INTEGER)');
    });
  }

  // Then you can use the database getter in another method
  Future<List<Task>> reading() async {
    Database DB = await instance.database;
    List<Map<String, dynamic>> maps = await DB.query(tname);
    return List.generate(maps.length, (i) {
     return Task.fromMap(maps[i]);
    });
  }
}
类SqlManager{
静态常量字符串tname='table1';
静态常量字符串dname='database.db';
//未来数据库;
//上单身班
SqlManager._privateConstructor();
静态最终SqlManager实例=SqlManager._privateConstructor();
//使用对数据库的单个引用。
静态数据库;
//使用此getter来使用数据库。
未来获取数据库异步{
if(_db!=null)返回_数据库;
//第一次访问数据库时实例化它
_db=等待_initDB();
返回_db;
}
//第一次初始化数据库。
_initDB()异步{
目录路径=等待getApplicationDocumentsDirectory();
return wait openDatabase(join(path.path,dname),版本:1,onCreate:(db,version){
返回db.execute(
'创建表$tname(id整型主键、名称文本、类型文本、time1整型、time2整型、imp整型、urg整型)';
});
}
//然后可以在另一种方法中使用数据库getter
Future reading()异步{
Database DB=wait instance.Database;
列表映射=等待DB.query(tname);
返回列表。生成(maps.length,(i){
返回Task.fromMap(maps[i]);
});
}
}
每当我试图调用这些函数中的任何一个时,我都会遇到NoSuchMethodError,它是由其中一个函数中的变量“DB”引发的。感谢您的帮助,谢谢

这是因为您尚未通过调用
initDB()
初始化数据库。因此,在使用数据库调用方法之前先调用它。但最后,您将为每个调用重新创建每个实例

更好的方法是为数据库创建一个单例。将您的
SqlManager
修改为如下内容:

class SqlManager { 
  static const String tname = 'table1';
  static const String dname = 'database.db';
  // Future<Database> db;

  // Make a singleton class
  SqlManager._privateConstructor();

  static final SqlManager instance = SqlManager._privateConstructor();

  // Use a single reference to the db.
  static Database _db;

  // Use this getter to use the database.
  Future<Database> get database async {
    if (_db != null) return _database;
    // Instantiate db the first time it is accessed
    _db = await _initDB();
    return _db;
  }

  // Init the database for the first time.
  _initDB() async {
    Directory path = await getApplicationDocumentsDirectory();
    return await openDatabase(join(path.path, dname), version: 1, onCreate: (db, version) {
     return db.execute(
         'CREATE TABLE $tname (id INTEGER PRIMARY KEY, name TEXT, type TEXT, time1 INTEGER, time2 INTEGER, imp INTEGER, urg INTEGER)');
    });
  }

  // Then you can use the database getter in another method
  Future<List<Task>> reading() async {
    Database DB = await instance.database;
    List<Map<String, dynamic>> maps = await DB.query(tname);
    return List.generate(maps.length, (i) {
     return Task.fromMap(maps[i]);
    });
  }
}
类SqlManager{
静态常量字符串tname='table1';
静态常量字符串dname='database.db';
//未来数据库;
//上单身班
SqlManager._privateConstructor();
静态最终SqlManager实例=SqlManager._privateConstructor();
//使用对数据库的单个引用。
静态数据库;
//使用此getter来使用数据库。
未来获取数据库异步{
if(_db!=null)返回_数据库;
//第一次访问数据库时实例化它
_db=等待_initDB();
返回_db;
}
//第一次初始化数据库。
_initDB()异步{
目录路径=等待getApplicationDocumentsDirectory();
return wait openDatabase(join(path.path,dname),版本:1,onCreate:(db,version){
返回db.execute(
'创建表$tname(id整型主键、名称文本、类型文本、time1整型、time2整型、imp整型、urg整型)';
});
}
//然后可以在另一种方法中使用数据库getter
Future reading()异步{
Database DB=wait instance.Database;
列表映射=等待DB.query(tname);
返回列表。生成(maps.length,(i){
返回Task.fromMap(maps[i]);
});
}
}

很高兴它能帮助您;)。这实际上是一个非常令人失望的问题。。。如果我们看一下,就会发现initDB()方法就是它,一个初始化方法。作为这类方法,initDB()必须是初始化的一部分,因此通常必须在构造函数中调用它。不幸的是,我们不能从那里调用它,因为我们不能使构造函数异步。。。(如果我们不等待,当构造函数“完成”时实例将不会“准备就绪”。)现在这个解决方案可以解决这个特定的问题,但是它可能不适用于其他异步初始化方法。很高兴它可以帮助您;)。这实际上是一个非常令人失望的问题。。。如果我们看一下,就会发现initDB()方法就是它,一个初始化方法。作为这类方法,initDB()必须是初始化的一部分,因此通常必须在构造函数中调用它。不幸的是,我们不能从那里调用它,因为我们不能使构造函数异步。。。(如果我们不等待,当构造函数“完成”时实例将不会“准备就绪”。)现在这个解决方案可以解决这个特定的问题,但是它可能不适用于其他一些异步init方法。