您的问题很可能与mDBHelper.getReadableDatabase();
也就是说,对于 Android 9+,默认日志记录已从 Journal 更改为 WAL(write=ahead logging)。
getReadableDatabase(或 getWritableDatabase)所做的是打开一个全新的空数据库并使用表 android_metadata 填充它。实际数据不是写入数据库文件而是写入-wal文件(即数据库文件名后缀-wal)。
复制数据库时,由 getReadableDatabase 创建的数据库将被覆盖,但 -wal(以及 -shm)文件仍然存在。所以当数据库被打开时,SQLite 检测到 -wal 文件不是正确的 -wal 文件并且无法打开它。SDK 通过创建一个新的空可用数据库来处理这个问题,因此找不到表名。
有许多修复。
您可以覆盖数据库助手的onConfigure方法并调用disableWriteAheadLogging
您可以将方法 getReadableDatabase 用于具有其他名称的数据库。
- 我从来没有遇到过这种情况,但理论上它会起作用。同样不建议这样做,因为它仍然相对资源匮乏。
如果 -wal 和 -shm 文件在复制之前或之后立即存在,您可以删除它们。
- 不建议这样做,因为它会浪费资源(打开数据库是相对昂贵的资源)。
您可以将getReadableDatabase替换为文件的mkdirs。那就是getReadableDatabase已经被编码,历史上,作为一个黑客来解决由于安装应用程序时数据库文件夹不存在而导致的 NO ENT 错误。
我建议不要在检查现有数据库之后实际执行此操作,而是使用基于以下内容的检查的一部分:-
private boolean checkDataBase(Context context, String databaseName) { /** * 不打开数据库,而是检查文件是否存在 * 如果不存在也会创建数据库目录 * (打开数据库的真正原因,这似乎会导致问题)*/
File db = new File(context.getDatabasePath(databaseName).getPath()); //Get the file name of the database
Log.d("DBPATH","DB Path is " + db.getPath()); //TODO remove for Live 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;
}
上面的代码取自A pre-populated database does not work at API 28 throws “no such table” 异常
,比较全面。
使固定
应用于您的代码,那么它可能是:-
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvProduct = (ListView) findViewById(R.id.listview_product);
mDBHelper = new DatabaseHelper(this);
File database = getApplicationContext().getDatabasePath(DatabaseHelper.DBNAME);
if (false == database.exists()) {
File dbdir = database.getParentFile();
if (!dbdir.exists()) {
database.getParentFile().mkdirs();
dbdir.mkdirs();
}
//Copy db
if (copyDatabase(this)) {
Toast.makeText(this, "Copy database succes", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(this, "Copy data error", Toast.LENGTH_SHORT).show();
return;
}
}
}