Android backup / restore: cómo hacer una copia de seguridad de una base de datos interna?

He implementado un BackupAgentHelper usando el FileBackupHelper proporcionado para respaldar y restaurar la base de datos nativa que tengo. Esta es la base de datos que normalmente utiliza junto con ContentProviders y que reside en /data/data/yourpackage/databases/ .

Uno podría pensar que este es un caso común. Sin embargo, los documentos no son claros sobre qué hacer: http://developer.android.com/guide/topics/data/backup.html . No hay BackupHelper específicamente para estas bases de datos típicas. Por lo tanto, utilicé FileBackupHelper , lo señalé a mi archivo .db en " /databases/ ", introduje bloqueos alrededor de cualquier operación db (como db.insert ) en mis ContentProviders e intenté crear el directorio " /databases/ " antes de onRestore() Porque no existe después de la instalación.

He implementado una solución similar para SharedPreferences éxito en una aplicación diferente en el pasado. Sin embargo, cuando LocalTransport mi nueva implementación en el emulador-2.2, veo una copia de seguridad que se realiza a LocalTransport de los registros, así como una restauración que se está realizando (y onRestore() llamado). Sin embargo, el archivo db en sí nunca se crea.

Tenga en cuenta que esto es todo después de una instalación, y antes del primer lanzamiento de la aplicación, después de que se haya realizado la restauración. Aparte de eso mi estrategia de prueba se basó en http://developer.android.com/guide/topics/data/backup.html#Testing .

Por favor, tenga en cuenta que no estoy hablando de alguna base de datos sqlite que me administre, ni sobre el respaldo de SDcard, servidor propio o en otro lugar.

Vi una mención en los documentos sobre las bases de datos que aconsejan utilizar un BackupAgent personalizado pero no parece relacionado:

Sin embargo, es posible que desee extender BackupAgent directamente si necesita: * Copia de seguridad de datos en una base de datos. Si tiene una base de datos SQLite que desee restaurar cuando el usuario vuelva a instalar su aplicación, debe crear un BackupAgent personalizado que lea los datos apropiados durante una operación de copia de seguridad, cree su tabla e inserte los datos durante una operación de restauración.

Un poco de claridad, por favor.

Si realmente necesito hacerlo yo mismo hasta el nivel de SQL, entonces estoy preocupado por los siguientes temas:

  • Abrir bases de datos y transacciones. No tengo ni idea de cómo cerrarlos de una clase singleton fuera del flujo de trabajo de mi aplicación.

  • Cómo notificar al usuario que una copia de seguridad está en curso y la base de datos está bloqueada. Puede tardar mucho tiempo, así que necesito mostrar una barra de progreso.

  • Cómo hacer lo mismo en la restauración. Según tengo entendido, la restauración puede ocurrir justo cuando el usuario ya ha comenzado a usar la aplicación (e introducir datos en la base de datos). Así que no puede presumir de restaurar los datos backupped en su lugar (eliminar los datos vacíos o antiguos). Usted tendrá que de alguna manera unirse a ella, que para cualquier base de datos no trivial es imposible debido a la identificación.

  • Cómo actualizar la aplicación después de la restauración se hace sin tener el usuario atascado en algún momento – ahora – punto inalcanzable.

  • ¿Puedo estar seguro de que la base de datos ya se ha actualizado en copia de seguridad o restauración? De lo contrario, el esquema esperado podría no coincidir.

Un enfoque más limpio sería crear un BackupHelper personalizado:

 public class DbBackupHelper extends FileBackupHelper { public DbBackupHelper(Context ctx, String dbName) { super(ctx, ctx.getDatabasePath(dbName).getAbsolutePath()); } } 

Y luego agregarlo a BackupAgentHelper :

 public void onCreate() { addHelper(DATABASE, new DbBackupHelper(this, DB.FILE)); } 

Después de revisar mi pregunta, pude conseguir que funcione después de ver cómo ConnectBot lo hace . Gracias Kenny y Jeffrey!

En realidad, es tan fácil como añadir:

 FileBackupHelper hosts = new FileBackupHelper(this, "../databases/" + HostDatabase.DB_NAME); addHelper(HostDatabase.DB_NAME, hosts); 

A su BackupAgentHelper .

El punto que faltaba era el hecho de que usted tendría que utilizar una trayectoria relativa con " ../databases/ ".

Sin embargo, esta no es una solución perfecta. Los documentos para FileBackupHelper mencionan por ejemplo: " FileBackupHelper debe utilizarse sólo con pequeños archivos de configuración, no con archivos binarios de gran tamaño. ", Siendo este último el caso de las bases de datos SQLite.

Me gustaría obtener más sugerencias, ideas sobre lo que se espera de nosotros (cuál es la solución adecuada), y consejos sobre cómo esto podría romper.

Aquí hay una forma más limpia de hacer copias de seguridad de las bases de datos como archivos. No hay caminos codificados.

 class MyBackupAgent extends BackupAgentHelper{ private static final String DB_NAME = "my_db"; @Override public void onCreate(){ FileBackupHelper dbs = new FileBackupHelper(this, DB_NAME); addHelper("dbs", dbs); } @Override public File getFilesDir(){ File path = getDatabasePath(DB_NAME); return path.getParentFile(); } } 

Nota: anula getFilesDir para que FileBackupHelper funcione en bases de datos dir, no archivos dir.

Otra pista: también puede utilizar databaseList para obtener todos los DB's y los nombres de feed de esta lista (sin ruta principal) en FileBackupHelper. A continuación, todos los DB de la aplicación se guardan en la copia de seguridad.

El uso de FileBackupHelper para realizar copias de seguridad / restaurar sqlite db plantea algunas preguntas serias:
1. ¿Qué sucede si la aplicación utiliza el cursor recuperado de ContentProvider.query() y el agente de copia de seguridad intenta anular todo el archivo?
2. El enlace es un buen ejemplo de prueba perfecta (baja entrophy;). Desinstala la aplicación, vuelve a instalarla y se restaura la copia de seguridad. Sin embargo la vida puede ser brutal. Echa un vistazo al enlace . Imaginemos un escenario cuando un usuario compra un nuevo dispositivo. Dado que no tiene su propio conjunto, el agente de copia de seguridad utiliza el conjunto de otro dispositivo. La aplicación está instalada y su backupHelper recupera el archivo antiguo con el esquema de la versión db más bajo que el actual. SQLiteOpenHelper llama a onDowngrade con la implementación predeterminada:

 public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { throw new SQLiteException("Can't downgrade database from version " + oldVersion + " to " + newVersion); } 

No importa lo que el usuario no puede usar su aplicación en el nuevo dispositivo.

Yo sugeriría usar ContentResolver para obtener datos -> serializar (sin _id s) para la copia de seguridad y deserializar -> insertar datos para restaurar.

Nota: obtener / insertar datos se realiza a través de ContentResolver, evitando problemas de moneda. La serialización se realiza en su backupAgent. Si hace su propia asignación de objeto cursor <-> la serialización de un elemento puede ser tan simple como implementar Serializable con campo transient _id en la clase que representa a su entidad.

También utilizaría insertar a granel el ejemplo de ContentProviderOperation CursorLoader.setUpdateThrottle y CursorLoader.setUpdateThrottle modo que la aplicación no se pegue con el cargador de la reanudación en el cambio de datos durante proceso de la restauración de la reserva.

Si se encuentra en una situación de degradación, puede optar por anular los datos de restauración o restaurar y actualizar ContentResolver con campos relevantes para la versión degradada.

Estoy de acuerdo en que el tema no es fácil, no se explica bien en documentos y algunas preguntas siguen siendo como el tamaño de datos a granel, etc

Espero que esto ayude.

A partir de Android M, ahora hay una API de copia de seguridad / restauración de datos completos disponible para las aplicaciones. Esta nueva API incluye una especificación basada en XML en el manifiesto de la aplicación, que permite al desarrollador describir qué archivos respaldar de una manera semántica directa: "copia de seguridad de la base de datos llamada" mydata.db ". Esta nueva API es mucho más fácil de usar para los desarrolladores: no es necesario realizar un seguimiento de los diffs o solicitar un pase de copia de seguridad de forma explícita, y la descripción XML de los archivos que se deben copiar significa que a menudo no es necesario escribir ningún código en absoluto.

(Puedes participar incluso en una operación de copia de seguridad / restauración de datos completos para obtener una devolución de llamada cuando sucede la restauración, por ejemplo.

Consulte la sección Configuración de la copia de seguridad automática para aplicaciones en developer.android.com para obtener una descripción de cómo utilizar la nueva API.

Una opción será construirlo en la lógica de la aplicación por encima de la base de datos. En realidad gritos para tal levell creo. No estoy seguro de si ya lo está haciendo, pero la mayoría de la gente (a pesar del enfoque de cursor de administrador de contenido de android) introducirá un mapeo de ORM – ya sea personalizado o algún enfoque orm-lite. Y lo que prefiero hacer en este caso es:

  1. Para asegurarse de que su aplicación funciona correctamente cuando la aplicación / datos se agrega en segundo plano con nuevos datos agregados / eliminados mientras la aplicación ya se ha iniciado
  2. Para hacer Java-> protobuf o incluso simplemente mapeo de serialización java y escribir su propio BackupHelper para leer los datos de la corriente y simplemente añadir a la base de datos ….

Así que en este caso en lugar de hacerlo en el nivel de db hacerlo en el nivel de aplicación.

  • Android SQLite ON CONFLICT UPDATE es posible?
  • ¿Cómo puedo reemplazar la imagen de mapa de bits después de girar la imagen original almacenada en cualquier lugar en el móvil?
  • Manejo de errores SQLException en android
  • ¿Debe haber un SQLiteOpenHelper para cada tabla en la base de datos?
  • Cómo insertar marca de tiempo en una columna de base de datos SQLite? Utilizando el tiempo de función ('ahora')?
  • Android cómo consultar enorme base de datos en android (tamaño del cursor está limitado a 1 MB)
  • Cómo pre-poblar una base de datos DAO sqlite verde
  • Android abrir o crear base de datos
  • NoSQL DB para Android que MongoDB y CouchDB?
  • Compruebe si la consulta SQL ha tenido éxito en Android SQLite
  • Pedido de datos con Firebase Android
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.