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