按照书上的代码仔细核对后,发现代码应该是没有问题的,只是无法查看表,在网上看见有人说使用版本低一点的模拟器就能解决这个问题,我试了一下,确实可以,这个是API 22的模拟器生成的databases文件夹下的文件截图
生成的这种类型的文件,直接导出.db
文件就可以在可视化工具中查看,并且这种情况和书上的也是一样的。
然后再放一张一开始我使用的模拟器(API28)生成的databases文件夹下的文件截图
从上图可以看到,在这个模拟器上生成的数据库文件是3个,这是因为在Android 9上,App的SQLite日志模式预设采用SQLite在3.7.0版加入的WAL (Write-Ahead Logging)模式。
第一张图SQLite使用rollback journal机制实现原子事务,rollback journal机制的原理是:在修改数据库文件中的数据之前,先将修改所在分页中的数据备份在另外一个地方,然后才将修改写入到数据库文件中;如果事务失败,则将备份数据拷贝回来,撤销修改;如果事务成功,则删除备份数据,提交修改。
第二张图采用WAL机制,WAL机制的原理是:修改并不直接写入到数据库文件中,而是写入到另外一个称为WAL的文件中;如果事务失败,WAL中的记录会被忽略,撤销修改;如果事务成功,它将在随后的某个时间被写回到数据库文件中,提交修改。同步WAL文件和数据库文件的行为被称为checkpoint(检查点),它由SQLite自动执行,默认是在WAL文件积累到1000页修改的时候;当然,在适当的时候,也可以手动执行checkpoint,SQLite提供了相关的接口。执行checkpoint之后,WAL文件会被清空。
现在我遇到的问题就是WAL文件并没有同步到DB文件,但是在这种情况下我们依旧是可以通过可视化工具查看数据库的数据,方法如下:
这是stackoverflow上给出的一个回复,简单概括就是在使用可视化工具查看数据库的时候,不应该只导出.db
文件,应该连同.db-wal
文件一起复制到工具中。这种方法确实是可行的。
经过上面的分析我们知道,当在Android 9 的设备上使用SQLite出现找不到表的问题的时候,可以有以下解决方法
1. 关闭WAL模式
两种方式:
(1)
@Override
public void onOpen(SQLiteDatabase db) {
super.onOpen(db);
//禁用WAL
db.disableWriteAheadLogging();
}
(2)
@Override
public void onConfigure(SQLiteDatabase db) {
super.onConfigure(db);
//禁用WAL
db.disableWriteAheadLogging();
}
2.手动执行CheckPoint
如何手动执行checkpoint,看SQLiteDatabase.endTransaction源码:
/**
* End a transaction. See beginTransaction for notes about how to use this and when transactions
* are committed and rolled back.
*/
public void endTransaction() {
verifyLockOwner();
try {
...
if (mTransactionIsSuccessful) {
execSQL(COMMIT_SQL);
// if write-ahead logging is used, we have to take care of checkpoint.
// TODO: should applications be given the flexibility of choosing when to
// trigger checkpoint?
// for now, do checkpoint after every COMMIT because that is the fastest
// way to guarantee that readers will see latest data.
// but this is the slowest way to run sqlite with in write-ahead logging mode.
if (this.mConnectionPool != null) {
execSQL("PRAGMA wal_checkpoint;");
if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
Log.i(TAG, "PRAGMA wal_Checkpoint done");
}
}
// log the transaction time to the Eventlog.
if (ENABLE_DB_SAMPLE) {
logTimeStat(getLastSqlStatement(), mTransStartTime, COMMIT_SQL);
}
} else {
...
}
} finally {
mTransactionListener = null;
unlockForced();
if (false) {
Log.v(TAG, "unlocked " + Thread.currentThread()
+ ", holdCount is " + mLock.getHoldCount());
}
}
}
也就是当我们执行endTransaction时会提交checkpoint。
3.更多没有试验的方法
参考文章链接:
https://www.sqlite.org/appfileformat.html
https://blog.csdn.net/degwei/article/details/9708339
https://blog.csdn.net/ws6013480777777/article/details/86493094