【发布时间】:2010-05-05 15:45:22
【问题描述】:
这个链接准确地描述了我的问题:http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218
现在大约有 300 人在使用我的 Android 应用程序,并且每次我都会通过此堆栈跟踪向服务器发送崩溃报告:
android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2596)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2621)
at android.app.ActivityThread.access$2200(ActivityThread.java:126)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1932)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.app.ActivityThread.main(ActivityThread.java:4595)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:521)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:860)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:618)
at dalvik.system.NativeStart.main(Native Method) Caused by: android.database.sqlite.SQLiteDatabaseCorruptException: database disk image is malformed
at android.database.sqlite.SQLiteQuery.native_fill_window(Native Method)
at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:75)
at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:295)
at android.database.sqlite.SQLiteCursor.getCount(SQLiteCursor.java:276)
at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:171)
at android.database.AbstractCursor.moveToFirst(AbstractCursor.java:248)
结果是应用程序崩溃,数据库中的所有数据都丢失了。
需要注意的一点是,每次我读取或写入数据库时,我都会获得一个新的 SQLiteDatabase,并在完成后立即关闭它。我这样做是为了防止此类损坏错误。
我还尝试使用单个静态对象同步所有数据库读取和写入,但这似乎没有帮助。
这可能只是一个 SQLite 错误吗?
我在这里发现了与内置电子邮件应用程序类似的错误:http://code.google.com/p/android/issues/detail?id=5610。
这是我的代码:
public class KeyValueTableAdapter extends BaseTableAdapter {
private String tableName;
private String keyColumnName;
private String valueColumnName;
public KeyValueTableAdapter(Context context, String tableName, String keyColumnName, String valueColumnName) {
super(context);
this.tableName = tableName;
this.keyColumnName = keyColumnName;
this.valueColumnName = valueColumnName;
}
protected String getStringValue(int key) {
Cursor cursor = null;
SQLiteDatabase db = null;
String value;
try {
db = dbOpenHelper.getReadableDatabase();
cursor = db.query(true, tableName, new String[] { valueColumnName }, keyColumnName + "=" + key, null, null, null, null, null);
if ((cursor.getCount() == 0) || !cursor.moveToFirst()) {
value = null;
} else {
value = cursor.getString(0);
}
} finally {
if (cursor != null) cursor.close();
if (db != null) db.close();
dbOpenHelper.close();
}
return value;
}
}
public abstract class BaseTableAdapter {
protected DbOpenHelper dbOpenHelper;
public BaseTableAdapter(Context context) {
this.dbOpenHelper = new DbOpenHelper(context, DatabaseSettings.DATABASE_NAME, null, DatabaseSettings.DATABASE_VERSION);
}
}
【问题讨论】:
-
您在数据库上使用触发器吗?
-
不,这个特定的表只是一个“键/值表”。两列:一个主键(整数)和另一个非空(文本)。你认为使用文本可能是问题吗?我对 SQLite 的打字有点不熟悉。
-
SQLite 是无类型的,这不算。您可以在日期字段中推送文本:)
-
这就是我的想法,而且它在 cursor.moveToFirst() 处失败,而不是 getString 或 getInt 或其他。
-
我有一个损坏的数据库问题,当我在事务中发出一些删除/创建表/视图/触发器时。事实证明,SQLite 事务只能保存特定于表的查询,而不是与架构相关的查询。