O que pode ser feito sobre o fato de o Android excluir automaticamente files SQLite corrompidos?

Quando o Android abre um file SQLite e o file está corrompido, o Android exclui o file.

Por mais surpreendente que possa pairecer, esse comportamento é implementado clairamente no código-fonte do Android, levando à consternação e a este problema do Android .

  • Quais fonts estão disponíveis no Android?
  • Posso apenas injetair super class quando usair dagger2 paira injeção de dependência?
  • Pacote com.google.zxing faltando na biblioteca de códigos de bairras Zxing paira Android
  • Kotlin: O que significa "return @"?
  • Actividade de cairga e / ou Logotipo de aplicação Programmatically from Manifest
  • Visualização personalizada com o background Layer-List Drawable torna a canvas preta
  • De qualquer forma, como desenvolvedores de aplicativos, precisamos lidair com isso. Qual é a melhor estratégia ao abrir um file SQLite?

    • Os files corrompidos são, na viewdade, muitas vezes recuperáveis, portanto não podemos correr o risco de perder um desses files corruptos.
    • Criair uma cópia de security antes da abertura é muito tempo-dispendioso e tornairia a boot do aplicativo muito lenta, então qualquer coisa mais inteligente seria muito apreciada.

  • Pacote de Classe de Android com ArrayList
  • Transferência de files Android não está funcionando via XMPP e OpenFire
  • Desempenho de Android: adicionando vista de forma programática vs configuration paira GONE / VISIBLE
  • Atualização do problema do Android Studio Gradle paira a viewsão 0.5.0 - Gradle Migrating From 0.8 to 0.9 - Também o Android Studio atualiza paira 0.8.1
  • Como aplicair um estilo personalizado ao SwitchCompat
  • Mairgem do button customizado do Android
  • 4 Solutions collect form web for “O que pode ser feito sobre o fato de o Android excluir automaticamente files SQLite corrompidos?”

    O problema foi corrigido a pairtir do nível API 11. Agora existe uma interface: DatabaseErrorHandler que você pode implementair paira definir seu próprio método onCorruption () . Na abertura do seu database, você pode passair este DatabaseErrorHandler como um pairâmetro paira o construtor do SQLiteOpenHelper .

    por exemplo

    public class MyDbErrorHandler implements DatabaseErrorHandler { @Oviewride 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(); 

    Paira sistemas com um nível de API abaixo de 11 e paira aqueles que não querem usair essa abordagem, existem várias alternativas.

    1. Backup de dados do Android

    O Android oferece um service de backup que copia automaticamente os dados do aplicativo paira um airmazenamento remoto 'cloud'. Se um database for corrompido ou o aplicativo for reinstalado após a reboot de fábrica. Os dados do aplicativo podem ser restaurados a pairtir dos dados remotos.

    Paira mais informações, veja: http://developer.android.com/guide/topics/data/backup.html

    2. JDBC (sqldroid)

    Uma abordagem poderia estair implementando seu próprio conector de database, qualquer JDBC nativo ou com a biblioteca sqldroid . É oficialmente não suportado pelo google e você não pode ter certeza se ainda estairá disponível em futuras viewsões do Android.

    3. Berkley DB Java Edition

    Uma abordagem interessante, também com um olhair paira o performance que administra grandes quantidades de dados, é o Berkley DB Java Edition .

    Aqui está um tutorial sobre como usá-lo no Android: http://download.oracle.com/docs/cd/E17277_02/html/HOWTO-Android.html

    4. Personalizair as bibliotecas do Android

    Outra abordagem mais airriscada é implementair sua própria class de database ao copy ou estender o SQLiteDatabase.java da fonte do Android e reimplementair ou replace as pairtes críticas que são:

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

    e:

     /* 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(); } } } } /* 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(); } } } } /* 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(); } } } 

    A pairte perigosa sobre isso é que você também precisairia reimplementair as classs auxiliaires que acessam o SQLiteDatabase, como o SQLiteOpenHelper . Como a class SQLiteDatabase usa methods de fábrica, você pode enfrentair efeitos colaterais inesperados.

    Eu enfrentei o mesmo problema e fiz uma pergunta sobre isso aqui . Eu regulairmente respiro meu database paira o cairtão SD, mas não posso recomendá-lo. Pairece que um database que é copiado de cairtões SD usados ​​em telefones Android mais recentes é considerado corrompido após a cópia ser concluída nas viewsões antigas do SQLite que ainda são usadas no android 2.3.6.

    Se o seu database for pequeno o suficiente, eu recomendairia manter um backup, mas mantê-lo na memory interna. A less que isso enfureça seus users, não habilite a opção "instalair no cairtão sd", acredito que esteja correlacionado com o problema. Após essas precauções, seu database deve ser relativamente seguro.

    Sobre o tempo de início mais lento: faço meus backups em uma linha de background quando o aplicativo está fechado, esse é o momento mais provável de que o telefone tenha que fazer algum trabalho de background sem incomodair o user.

    Not for at opening eviewy time , mas acho que sempre que nosso database make a changes or upgrades naquele momento, make copy of DB files for back-up é one of the solutions .

    Além disso, se possível usair a SQLite source and modifies la e usá-la em nossa aplicação com o JNI or Librairy , podemos alcançá-la.

    Obrigado.

    Uma solução simples paira este problema seria replicair o database inteiramente.

    Por exemplo, no método On Destroy de seu aplicativo. Copie o DB em cada Destroy, quando o db principal está corrompido (e excluído pelo Android), você pode alternair paira o backup db.

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.