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

当Android打开一个SQLite文件,并且该文件已损坏,Android 删除该文件。

令人惊讶的是,这种行为在Android源代码中清楚地实现,导致了这个Android问题 。

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

  • 损坏的文件实际上通常是可恢复的,所以我们不能承担任何损失这些损坏文件的风险。
  • 在打开之前创build备份非常耗时,并且会使应用程序的启动速度非常慢,所以更聪明的东西将不胜感激。

Solutions Collecting From Web of "关于Android自动删除损坏的SQLite文件的事实可以做些什么?"

该问题已从API级别11开始修复。现在存在一个接口: DatabaseErrorHandler ,您可以使用该接口来定义您自己的onCorruption()方法。 在数据库打开时,您可以将此DatabaseErrorHandler作为parameter passing给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的系统,对于那些不想使用这种方法的系统,有几种select。

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; } 

和:

 /* 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类使用工厂方法,您可能会遇到意想不到的副作用。

我面临同样的问题,并在这里问了一个问题。 我经常备份我的数据库到SD卡,但我不能推荐它。 看起来好像从较新的Android手机中使用的SD卡中复制的数据库在Android 2.3.6上仍旧使用的较旧版本的SQLite上完成复制之后被认为已损坏。

如果你的数据库足够小,那么我会build议保留一个备份,但保留在内部存储器上。 除非它会激怒你的用户,否则不要启用“安装到SD卡”选项,我相信这是相关的问题。 这些预防措施后,你的数据库应该是相对安全的。

关于较慢的开始时间:当应用程序closures时,我在后台线程中执行备份,这是手机最有可能执行一些后台工作而不会影响用户的时间。

Not for at opening every time ,但是我认为当我们的database make a changes or upgrades在这个时候make copy of DB files for back-up 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应用程序中使用它,那么我们可以实现它。

谢谢。

解决这个问题的一个简单的办法是完全复制数据库。

例如在你的应用程序的Destroy方法。 在每个Destroy上复制数据库,当主数据库损坏(并被android删除)时,可以切换到备份数据库。