在 Android 本机中访问使用 Flutter 创建的数据库时获取 SQLiteException

Getting SQLiteException while accessing the database created with Flutter in Android native

我在 Android 本机中遇到错误 no such table。数据库是用 Flutter sqflite 包创建的。数据库存在于目录中。数据库和 table 名称被检查并确认了不止一次。我不知道本机代码有什么问题。它与 Dart/Flutter.

一起工作得很好

我们是否无法访问 Dart/Flutter 在 Android 原生中创建的数据库,或者方法有些不同?

Android 侧的代码。

public static Cursor getDB(Context context){
        myDB = SQLiteDatabase.openDatabase(context.getDatabasePath(DB_NAME).getAbsolutePath(), null, SQLiteDatabase.OPEN_READWRITE);
        String query = "SELECT * FROM todo";
        return myDB.rawQuery(query, null);
}

数据库创建Dart代码

final String _DB_NAME = "todos.db";
final String tableTodo = 'todo';
final String columnId = '_id';
final String columnTitle = 'title';

  Future<Database> initializeDB() async {
    String dbDir = await getDatabasesPath();
    String dbPath = dbDir + _DB_NAME;
    var database = await openDatabase(dbPath, version: 1, onCreate: _createDB);
    return database;
  }

  void _createDB(Database db, int version) async {
    await db.execute(
        'create table $tableTodo ($columnId INTEGER PRIMARY KEY AUTOINCREMENT, $columnTitle TEXT NOT NULL)');
  }

提前致谢!

您可能没有打开同一个数据库。看来你没有在 flutter 方面正确构建 dbPath 。如果你简单地打印它,你应该看到你在路径

中缺少一个 /

而不是

String dbPath = dbDir + _DB_NAME;

尝试(从 path 套餐加入):

var dbPath = join(dbDir, _DB_NAME);

或者干脆

var dbPath = _DB_NAME;

I am getting an error no such table in Android native.

如果数据库不存在,Android SQLite API 的 openDatabase 方法将在给定路径创建一个空数据库。

table not foundno file existing at the specified path (根本原因很可能在后面介绍的Flutter代码中).

理想情况下,您应该在打开数据库之前检查文件是否存在。

所以沿着 :-

public static Cursor getDB(Context context){
     if (context.getDatabasePath(DB_NAME).exists()) {
        myDB = SQLiteDatabase.openDatabase(context.getDatabasePath(DB_NAME).getAbsolutePath(), null, SQLiteDatabase.OPEN_READWRITE);
        String query = "SELECT * FROM todo";
        return myDB.rawQuery(query, null);
    } else {
        // handle the file not existing
    }
}

The database exists in the dir.

如前所述,数据库将在事后存在。上面的代码检查文件(它不会进一步检查返回的文件是否是普通文件(File 的 isFile() 方法)或可以进行的其他检查)

  • 其他检查可能是:-
    • 检查文件的长度应至少为 4k,如果它有用户定义的 table 并且您已使用 AUTOINCREMENT(这会创建另一个内部 table sqlite_sequence) 至少 12k(每个 table 至少 4k,包括始终存在的 sqlite_master table) .

    • 打开文件并检查文件头的前 16 个字节应符合 SQLite Database File Format

      • 每个有效的 SQLite 数据库文件都以以下 16 个字节(十六进制)开头:53 51 4c 69 74 65 20 66 6f 72 6d 61 74 20 33 00。此字节序列对应于 UTF -8 字符串 "SQLite format 3" 包括末尾的 nul 终止符。
    • 使用 openDatabase 方法打开数据库后,您可以检查 sqlite_master 以查看 table(s) 是否按预期存在。

Is it like we can't access the database created with Dart/Flutter in Android native or the approach is somehow different?

从对 SQlite plugin for Flutter 的快速扫描中可以看出:-

A SQLite database is a file in the file system identified by a path. If relative, this path is relative to the path obtained by getDatabasesPath(), which is the default database directory on Android and the documents directory on iOS.

这表明Flutter使用了getDatabasePath()方法,因此看起来它们是兼容的,并且可能Flutter使用底层原生android sqlite api.

查看 documentation 似乎您没有按照建议打开数据库。给出的示例使用:-

// Get a location using getDatabasesPath
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'demo.db');

猜测添加文件分隔符然后 demo.db 所以而不是 data/data//databasetodos.db (看起来是由您的代码生成的) 上面的示例将使用 (如果 demo.db 更改为 todos.db) /data/data//databases/todos.db

  • 您可能希望检查是否存在这样的文件,并可能相应地移动和重命名它(这样可以避免重新生成任何数据,但您可能无法访问该文件)

因此我认为您的 Flutter 代码应该是:-

final String _DB_NAME = "todos.db";
final String tableTodo = 'todo';
final String columnId = '_id';
final String columnTitle = 'title';

  Future<Database> initializeDB() async {
    String dbDir = await getDatabasesPath();
    String dbPath = join(dbDir,_DB_NAME);
    var database = await openDatabase(dbPath, version: 1, onCreate: _createDB);
    return database;
  }

  void _createDB(Database db, int version) async {
    await db.execute(
        'create table $tableTodo ($columnId INTEGER PRIMARY KEY AUTOINCREMENT, $columnTitle TEXT NOT NULL)');
  }