Подтвердить что ты не робот

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

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

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

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

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

Ответ 1

Проблема исправлена, начиная с уровня 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 предлагает услугу резервного копирования, которая автоматически копирует данные приложения в удаленное облачное хранилище. Если база данных повреждена или приложение переустановлено после factory reset. Данные приложения могут быть восстановлены из удаленных данных.

Для получения дополнительной информации см.: 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 использует методы factory, вы можете столкнуться с неожиданными побочными эффектами.

Ответ 2

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

Если ваша база данных достаточно мала, я бы рекомендовал сохранить резервную копию, но сохранил ее во внутренней памяти. Если это не вызовет ярость ваших пользователей, не включите "install to sd-card" -option, я считаю, что это связано с этой проблемой. После этих предосторожностей ваша база данных должна быть относительно безопасной.

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

Ответ 3

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, тогда мы сможем его достичь.

Спасибо.

Ответ 4

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

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