gpt4 book ai didi

java - 在 Oreo 上复制 SQLite 数据库

转载 作者:搜寻专家 更新时间:2023-10-30 23:26:42 26 4
gpt4 key购买 nike

在我的一个 Android 应用程序中,我使用了一个预填充的数据库,我在第一次使用时复制了该数据库。到目前为止,这在所有 Android 版本上运行良好,但对于 API 28,它会失败。它确实复制了数据库,之后它可以连接到数据库,但由于某种原因,无法访问任何表。我得到该表不存在的错误。

我在模拟器上下载了数据库,检查了一下,数据库没有问题。我在代码中创建数据库的另一个应用程序运行良好(创建数据库后可以找到表)。

我用来复制数据库的代码:

public void copyDatabase() throws IOException{
InputStream myInput = mContext.getAssets().open(mDbSource);

// Path to the just created empty db
String outFileName = getDbPath() + mDbName;

//Open the empty db as the output stream
OutputStream myOutput = new FileOutputStream(outFileName);

//transfer bytes from the inputfile to the outputfile
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}

//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
}

private String getDbPath(){
return "/data/data/"+mContext.getResources().getString(R.string.package_name)+"/databases/";
}

API 28 中是否有任何更改导致此操作因某种原因失败?这可能是什么原因造成的?

最佳答案

API 28 开启的问题是 WAL(预写日志记录)在默认情况下处于开启状态。通常情况下,如果打开数据库(通常在检查数据库是否存在时完成),则会创建两个文件 -wal 和 -shm 文件。

例如在您的代码中,这似乎表明这就是您正在做的事情:-

// Path to the just created empty db
String outFileName = getDbPath() + mDbName;

当现有数据库被副本覆盖时,-wal 和 -shm 文件仍然存在。

当最终尝试将数据库作为 SQLiteDatabase 打开时,会引发数据库与 -wal 和 -shm 文件之间的不匹配。底层的 SQLiteDatabase open 然后决定数据库无法打开,因此,为了提供可用的数据库,删除并重新创建数据库有效地清空数据库,因此出现这种情况。

三种解决方法

  1. 覆盖 onConfigure 方法并强制它使用旧的日志模式(使用 [disableWriteAheadLogging](https://developer.android.com/reference/android/arch/persistence/db/SupportSQLiteDatabase#disablewriteaheadlogging 方法))。
  2. 使用 SQLiteDatabase 打开方法检查数据库是否存在,但要检查文件是否存在。
  3. 作为复制的一部分,删除 -wal 和 -shm 文件。

我建议 2 或 3 是更好的方法:-

  • 没有不必要的打开(和创建)数据库的开销,只是检查它是否存在并创建目录。
  • 由于 advantages of a WAL,该应用程序可能会得到改进通过日志记录。

以上内容均在Ship android app with pre populated database中涵盖.

解决方案代码实际上结合了 2 和 3(尽管应该不需要修复 3(因为修复 2 不会将数据库作为 SQLiteDatabase 打开))。

说我相信以下用于检查数据库是否存在的代码(修复 2)比上面答案中的等效代码更好:-

/**
* Check if the database already exists. NOTE will create the databases folder is it doesn't exist
* @return true if it exists, false if it doesn't
*/
public static boolean checkDataBase(Context context, String dbname) {

File db = new File(context.getDatabasePath(dbname).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove if publish App
if (db.exists()) return true; // If it exists then return doing nothing

// Get the parent (directory in which the database file would be)
File dbdir = db.getParentFile();
// If the directory does not exits then make the directory (and higher level directories)
if (!dbdir.exists()) {
db.getParentFile().mkdirs();
dbdir.mkdirs();
}
return false;
}

关于java - 在 Oreo 上复制 SQLite 数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56241576/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com