问题描述
最近我收到了很多关于 HTC Desire 系列的抱怨,它在调用 sql 语句时失败.我收到了来自用户的报告,其中包含包含以下内容的日志快照.
Recently I have been getting a lot of complaints about the HTC Desire series and it failing while invoking sql statements. I have received reports from users with log snapshots that contain the following.
I/Database( 2348): sqlite returned: error code = 8, msg = statement aborts at 1: [pragma journal_mode = WAL;]
E/Database( 2348): sqlite3_exec to set journal_mode of /data/data/my.app.package/files/localized_db_en_uk-1.sqlite to WAL failed
接下来是我的应用程序基本上着火了,因为打开数据库的调用会导致严重的运行时错误,表现为游标保持打开状态.此时不应该有游标,因为我们正在尝试打开它.
followed by my app basically burning in flames because the call to open the database results in a serious runtime error that manifests itself as the cursor being left open. There shouldn't be a cursor at this point as we are trying to open it.
这只发生在 HTC Desire HD 和 Z 上.我的代码基本上做了以下事情(做了一点改动以隔离问题区域).
This only occurs with the HTC Desire HD and Z. My code basically does the following (changed a little to isolate the problem area).
SQLiteDatabase db;
String dbName;
public SQLiteDatabase loadDb(Context context) throws IOException{
//Close any old db handle
if (db != null && db.isOpen()) {
db.close();
}
// The name of the database to use from the bundled assets.
String dbAsset = "/asset_dir/"+dbName+".sqlite";
InputStream myInput = context.getAssets().open(dbAsset, Context.MODE_PRIVATE);
// Create a file in the app's file directory since sqlite requires a path
// Not ideal but we will copy the file out of our bundled assets and open it
// it in another location.
FileOutputStream myOutput = context.openFileOutput(dbName, Context.MODE_PRIVATE);
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer)) > 0) {
myOutput.write(buffer, 0, length);
}
// Close the streams
myOutput.flush();
// Guarantee Write!
myOutput.getFD().sync();
myOutput.close();
myInput.close();
// Not grab the newly written file
File fileObj = context.getFileStreamPath(dbName);
// and open the database
return db = SQLiteDatabase.openDatabase(fileObj.getAbsolutePath(), null, SQLiteDatabase.OPEN_READONLY | SQLiteDatabase.NO_LOCALIZED_COLLATORS);
}
遗憾的是,这款手机仅在英国有售,我的库存中没有.我只从 HTC Desire 系列中得到这种类型的报告.我不知道发生了什么变化,因为这段代码一直工作没有任何问题.有什么我遗漏的吗?
Sadly this phone is only available in the UK and I don't have one in my inventory. I am only getting reports of this type from the HTC Desire series. I don't know what changed as this code has been working without any problem. Is there something I am missing?
推荐答案
简短回答:尝试删除 SQLiteDatabase.OPEN_READONLY
.
Short answer: try removing SQLiteDatabase.OPEN_READONLY
.
更长的答案:
WAL"是预写日志,据我所知,这是 SQLite 中相对较新的功能.WAL 上的 SQLite 文档说不可能打开只读 WAL 数据库."现在,这似乎更适用于只读媒体,但它可能适用于 OPEN_READONLY
.
The "WAL" is the write-ahead log, a relatively new feature in SQLite as I understand it. The SQLite docs on WAL say "It is not possible to open read-only WAL databases." Now, that appears to be more in the context of read-only media, but it might hold true for OPEN_READONLY
.
如果这有帮助,我会感到有些惊讶,因为它假定:
I'd be somewhat surprised if this helps, as it presumes that:
- WAL 未在标准 Android 中使用
- HTC 在这两款设备中启用了 WAL
- 您的环境的一些特殊情况(例如,您从资产中提取的二进制数据库)导致了这个问题,其中普通的只读数据库仍然可以正常工作,因为我无法想象这些设备会通过兼容性测试损坏的只读数据库支持
但是,我认为至少值得一试.
But, I would think it is at least worth a shot.
您还可以考虑从打包二进制数据库切换到打包 SQL 语句以构建/填充数据库并执行它们.虽然这会更慢(如果您不使用事务会更慢),但它可能不太容易出现特定于数据库文件的问题.
You might also consider switching from packaging the binary database to packaging the SQL statements to build/populate the database and executing them. While this will be slower (much slower if you don't use transactions), it might be less prone to database file-specific issues.
这篇关于HTC Desire HD 的 Sqlite 问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!