Что можно сделать с тем, что Android автоматически удаляет поврежденные файлы SQLite? - PullRequest
19 голосов
/ 14 октября 2011

Когда Android открывает файл SQLite и файл поврежден, Android удаляет файл.

Как ни удивительно, это поведение четко реализовано в исходном коде Android, что приводит к ужасу и к этой проблеме с Android .

В любом случае, как разработчики приложений, мы просто должны иметь с этим дело. Какова наилучшая стратегия при открытии файла SQLite?

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

Ответы [ 4 ]

10 голосов
/ 14 октября 2011

Проблема была исправлена, начиная с уровня API 11. Теперь существует интерфейс: DatabaseErrorHandler , который вы можете реализовать, чтобы определить свой собственный метод onCorruption () .При открытии вашей базы данных вы можете передать этот DatabaseErrorHandler в качестве параметра конструктору SQLiteOpenHelper .

например,

public class MyDbErrorHandler implements DatabaseErrorHandler {
    @Override
    onCorruption(SQLiteDatabase db) {
        // Back up the db or do some other stuff
    }
}

SQLiteOpenHelper dbHelper = new SQLiteOpenHelper(context, "MyDbName", null, 1,
                                                 new MyDbErrorHandler());

SQLiteDatabase db = dbHelper.getWritableDatabase();

Для системс уровнем API ниже 11 и для тех, кто не хочет использовать этот подход, есть несколько альтернатив.

1.Резервное копирование данных Android

Android предлагает сервис резервного копирования, который автоматически копирует данные приложения в удаленное «облачное» хранилище.Если база данных повреждена или приложение переустановлено после сброса настроек.Данные приложения могут быть восстановлены из удаленных данных.

Для получения дополнительной информации см .: http://developer.android.com/guide/topics/data/backup.html

2.JDBC (sqldroid)

Одним из подходов может быть реализация собственного коннектора базы данных, либо собственного JDBC, либо с библиотекой sqldroid .Он официально не поддерживается Google, и вы не можете быть уверены, будет ли он по-прежнему доступен в будущих версиях Android.

3.Berkley DB Java Edition

Интересным подходом, также с точки зрения производительности, обрабатывающей большие объемы данных, является Berkley DB Java Edition .

Вот руководство по использованию в Android: http://download.oracle.com/docs/cd/E17277_02/html/HOWTO-Android.html

4.Настройка библиотек Android

Еще один более рискованный подход заключается в реализации собственного класса базы данных путем копирования или расширения SQLiteDatabase.java из источника Android и переопределения или переопределения критических частей:

public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags) {
    SQLiteDatabase sqliteDatabase = null;
    try {
        // Open the database.
        sqliteDatabase = new SQLiteDatabase(path, factory, flags);
        if (SQLiteDebug.DEBUG_SQL_STATEMENTS) {
            sqliteDatabase.enableSqlTracing(path);
        }
        if (SQLiteDebug.DEBUG_SQL_TIME) {
            sqliteDatabase.enableSqlProfiling(path);
        }
    } catch (SQLiteDatabaseCorruptException e) {
        // Try to recover from this, if we can.
        // TODO: should we do this for other open failures?
        Log.e(TAG, "Deleting and re-creating corrupt database " + path, e);
        EventLog.writeEvent(EVENT_DB_CORRUPT, path);
        if (!path.equalsIgnoreCase(":memory")) {
            // delete is only for non-memory database files
            new File(path).delete();
        }
        sqliteDatabase = new SQLiteDatabase(path, factory, flags);
    }
    ActiveDatabases.getInstance().mActiveDatabases.add(
            new WeakReference<SQLiteDatabase>(sqliteDatabase));
    return sqliteDatabase;
}

и:

/* package */ void onCorruption() {
    Log.e(TAG, "Removing corrupt database: " + mPath);
    EventLog.writeEvent(EVENT_DB_CORRUPT, mPath);
    try {
        // Close the database (if we can), which will cause subsequent operations to fail.
        close();
    } finally {
        // Delete the corrupt file.  Don't re-create it now -- that would just confuse people
        // -- but the next time someone tries to open it, they can set it up from scratch.
        if (!mPath.equalsIgnoreCase(":memory")) {
            // delete is only for non-memory database files
            new File(mPath).delete();
        }
    }
}

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

2 голосов
/ 14 октября 2011

Я столкнулся с той же проблемой и задал вопрос об этом здесь .Я регулярно делаю резервную копию своей базы данных на SD-карту, но я не могу рекомендовать это.Похоже, что база данных, которая копируется с SD-карт, используемых в новых телефонах Android, считается поврежденной после завершения копирования на более старых версиях SQLite, которые все еще используются на Android 2.3.6.

Если вашбаза данных достаточно мала, поэтому я бы порекомендовал сохранить резервную копию, но хранить ее во внутренней памяти.Если это не разозлит ваших пользователей, не включайте опцию «установить на SD-карту», ​​я полагаю, что это связано с проблемой.После этих мер предосторожности ваша база данных должна быть относительно безопасной.

О более медленном времени запуска: я делаю свои резервные копии в фоновом потоке, когда приложение закрыто, это наиболее вероятный момент, когда телефон должен сделать некоторый фонработать без беспокойства пользователя.

1 голос
/ 14 октября 2011

Not for at opening every time, но я думаю, что каждый раз, когда database make a changes or upgrades в это время make copy of DB files for back-up - это one of the solutions.

Также, если возможно использовать SQLite source and modifies и использовать его в нашем приложении с JNI or Library, тогда мы можем достичь этого.

Спасибо.

0 голосов
/ 14 октября 2011

Простым решением этой проблемы было бы полное копирование БД.

Например, в методе on Destroy вашего приложения. Скопируйте БД на каждый Destroy, когда основная БД повреждена (и удалена Android), вы можете переключиться на резервную БД.

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