База данных 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)

Результатом является катастрофический отказ приложения и все данные в потерянном DB.

Одна вещь отметить состоит в том, что каждый раз я читал или пишу в базу данных, я получаю новый SQLiteDatabase и закрываю его, как только я сделан. Я сделал это в попытке предотвратить подобные ошибки повреждения.

Я также пытался синхронизировать все чтения DB и записи с помощью единственного статического объекта, и это, казалось, не помогло.

Действительно ли возможно, что это - просто ошибка 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);
    }

}

9
задан Brandon O'Rourke 17 May 2010 в 21:11
поделиться

5 ответов

"БД хранит информацию о сеансе, поэтому резервное копирование нереально. Данные меняются поминутно "

Вам следует попробовать использовать 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

См. getSharedPreferences и SharedPreferences для более подробного описания.

-3
ответ дан 4 December 2019 в 21:08
поделиться

Скорее всего, процесс (а) базы данных прекращает работу во время ввода-вывода. Например, убийцей задач, или если вы разрешаете выполнение операций записи в базу данных в то время, когда приложение должно выключиться или перейти в спящий режим ...

Посмотрите, сможете ли вы воспроизвести проблему, поместив свое приложение в цикл записи базы данных и используя на нем убийцу задач.

Сценарий: 32 байта записываются в базу данных, задача записи завершается после записи только 10, результат: база данных остается в несогласованном и, возможно, поврежденном состоянии.

См. Также: Убийца процессов Android

РЕДАКТИРОВАТЬ: открывать и закрывать БД для каждого чтения / записи? прекрати это! :)

9
ответ дан 4 December 2019 в 21:08
поделиться

Использование нескольких экземпляров SQLiteDatabase может быть причиной проблемы, если два экземпляра одновременно обновляют один и тот же файл базы данных.

2
ответ дан 4 December 2019 в 21:08
поделиться

Реализуйте процесс резервного копирования базы данных каждый день, и если база данных будет повреждена, вы просто замените базу данных резервной копией. Вы можете использовать простые методы копирования и вставки файлов для ежедневного резервного копирования.

1
ответ дан 4 December 2019 в 21:08
поделиться

Поскольку я пока не могу комментировать сообщение Брэда.

Я согласен с дополнительными накладными расходами.

У меня HTC Magic в качестве повседневного телефона, и оперативная память всегда является проблемой.

Android-телефоны находятся на очень разных концах $ $ $.

Некоторые из них очень дешевы, а некоторые очень дороги, в основном это связано с оперативной памятью и процессором.

Люди, которые запускают таск-киллеры, действительно портят свои телефоны на базе Android.

Как разработчик, вы должны предлагать людям не использовать их или просто отказывать в поддержке тем, кто использует убийцы задач, поскольку Android не нуждается в этих «улучшениях» (спросите у Стива (cyanogen))

Также new в android стоит очень дорого.

Вы хотите ограничить количество новых вызовов при программировании для Android.

Программирование для Android - это повторное использование драгоценной памяти. (В HTC Magics / Dreams для приложений доступно только 96 МБ, и большая часть из них уже используется)

Что касается вашего SQLiteDB ... API сообщает, что ваш SQLiteDB является частным для вашего приложения.

Я не понимаю, почему вам нужно открывать и закрывать НОВОЕ соединение с ним каждый раз, когда вы хотите читать или писать в него.

Я бы предпочел оставить соединение открытым до тех пор, пока пользователь не потеряет от него фокус.

Однако, если вы пишете поставщику контента, это совсем другая история.

1
ответ дан 4 December 2019 в 21:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: