База данных Android SQLite повреждена - PullRequest
8 голосов
/ 05 мая 2010

Эта ссылка точно описывает мою проблему: http://old.nabble.com/Android-database-corruption-td28044218.html#a28044218

Сейчас моим приложением для Android пользуются около 300 человек, и каждый раз, когда я получаю отчет о сбое на сервере со следующей трассировкой стека:

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)

В результате происходит сбой приложения и потеря всех данных в БД.

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

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

Возможно ли, что это просто ошибка 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 ]

9 голосов
/ 05 мая 2010

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

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

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

См. Также: Android process killer

EDIT: открывать и закрывать БД для каждой операции чтения / записи?прекрати это!:)

2 голосов
/ 05 мая 2010

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

1 голос
/ 17 мая 2010

Так как я не могу комментировать -ет- пост Брэда.

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

Мой ежедневный телефон - HTC Magic, и оперативная память - это всегда проблема.

Телефоны Android находятся на совершенно разных концах $$$

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

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

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

Также оператор new в Android очень дорогой.

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

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

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

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

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

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

1 голос
/ 13 мая 2010

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

0 голосов
/ 15 мая 2010

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...