关于Android自动删除损坏的SQLite文件这一事实可以做些什么?

Nic*_*oul 19 sqlite android

当Android打开SQLite文件并且文件损坏时,Android 会删除该文件.

虽然听起来很令人惊讶,但这种行为在Android源代码中清晰地实现,导致惊愕和Android问题.

无论如何,作为应用程序开发人员,我们只需处理它.打开SQLite文件时最好的策略是什么?

  • 实际上,损坏的文件通常是可以恢复的,因此我们承担不起丢失其中一个损坏文件的风险.
  • 在打开之前创建备份是非常耗时的,并且会使应用程序启动非常慢,所以任何更聪明的东西都会非常感激.

Dyo*_*sos 10

该问题已从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();
Run Code Online (Sandbox Code Playgroud)

对于API级别低于11的系统,对于那些不想使用此方法的系统,有几种选择.

1. Android数据备份

Android提供备份服务,可自动将应用程序数据复制到远程"云"存储.如果数据库损坏或在出厂重置后重新安装应用程序.可以从远程数据恢复应用程序数据.

有关详细信息,请参阅:http: //developer.android.com/guide/topics/data/backup.html

2. JDBC(sqldroid)

一种方法可能是实现您自己的数据库连接器,本机JDBC或sqldroid库.谷歌官方不支持它,你不能确定它是否仍然可以在未来的Android版本中使用.

3. Berkley DB Java版

Berkley DB Java版是一种有趣的方法,也是一种处理大量数据的性能处理方法.

以下是如何在Android中使用它的教程:http://download.oracle.com/docs/cd/E17277_02/html/HOWTO-Android.html

4.自定义android库

另一种更危险的方法是通过从android源代码复制或扩展SQLiteDatabase.java来实现自己的数据库类,并重新实现或覆盖以下关键部分:

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;
}
Run Code Online (Sandbox Code Playgroud)

和:

/* 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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

关于这一点的危险部分是,您还必须重新实现访问SQLiteDatabase的帮助程序类,例如SQLiteOpenHelper.由于SQLiteDatabase课程使用工厂方法,您可能会遇到意想不到的副作用.