Android SQLite数据库已损坏

时间:2010-05-05 15:45:22

标签: android sqlite

此链接完全描述了我的问题: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);
    }

}

5 个答案:

答案 0 :(得分:9)

数据库进程很可能在I / O期间被杀死。例如,通过任务杀手,或者如果您允许数据​​库写入操作在应用程序关闭或休眠期间继续...

看看你是否可以通过将你的应用程序置于数据库写入循环并在其上使用任务杀手来重现该问题。

场景:写入数据库的字节为32个字节,写入任务仅在写入10后被杀死,结果:数据库处于不一致且可能已损坏的状态。

另见: Android process killer

编辑:为每次读/写打开和关闭数据库?不要那么做! :)

答案 1 :(得分:2)

如果有两个实例同时更新同一个数据库文件,则使用SQLiteDatabase的多个实例可能会导致您的问题。

答案 2 :(得分:1)

每天实施一个备份数据库进程,如果数据库损坏,您只需用备份替换数据库。您可以使用简单的文件复制粘贴方法来维护每天的备份。

答案 3 :(得分:1)

因为我无法对Brad的帖子发表评论。

我必须同意额外的开销。

我有一个HTC Magic作为我的日常电话,而ram总是一个问题。

Android手机与$$$

截然不同

有些超级便宜,有些超级贵,这基本上归结为ram和cpu。

运行任务杀手的人确实破坏了他们的Android手机。

作为开发者,你应该建议人们不要使用它们,或者只是拒绝支持使用任务杀手的人,因为android不需要这些“改进”(问steve(cyanogen))

android中的new语句也非常昂贵。

您希望在为Android编程时限制new调用的数量。

android的编程就是重用宝贵的内存。 (HTC Magics / Dreams只有96MB可用于应用程序,其中大部分已经在使用中)

对于您的SQLiteDB ...... API表示您的SQLiteDB对您的应用程序是私有的。

我不明白为什么每次想要阅读或写入时都需要打开和关闭它的新连接。

我宁愿保持连接打开,直到用户失去焦点。

但是,如果您正在撰写内容提供商,那就是另一回事了。

答案 4 :(得分:-3)

  

“数据库保存会话信息   做备份不太可行。   数据按分钟“

更改

您应该尝试使用SharedPreferences:它存储键值对(在后台,它使用文件)。 存储值:

SharedPreferences sp=MyActivity.getSharedPreferences("Name", Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString("key", value);
editor.putBoolean("another", true);
editor.commit();

检索数据:

sp.getString("key", "Not found"); 
// "Not found" is the default value
// if sp does not contain the specified key
sp.getBoolean("another", false); 
// false is the default value
// if sp does not contain the specified key

有关更详细的说明,请参阅getSharedPreferencesSharedPreferences