Implementé un BackupAgentHelper
uso del proporcionado FileBackupHelper
para hacer una copia de seguridad y restaurar la base de datos nativa que tengo. Esta es la base de datos que normalmente usa junto con ContentProviders
y en la que reside /data/data/yourpackage/databases/
.
Uno pensaría que este es un caso común. Sin embargo, los documentos no están claros sobre qué hacer: http://developer.android.com/guide/topics/data/backup.html . No hayBackupHelper
específicamente para estas bases de datos típicas. Por lo tanto, utilicé elFileBackupHelper
, apunté a mi archivo .db en " /databases/
", introduje bloqueos alrededor de cualquier operación db (como db.insert
) en my ContentProviders
, e incluso intenté crear el /databases/
directorio " " antes onRestore()
porque no existe después de la instalación.
He implementado una solución similar con SharedPreferences
éxito en una aplicación diferente en el pasado. Sin embargo, cuando pruebo mi nueva implementación en el emulador-2.2, veo que se realiza una copia de seguridad LocalTransport
desde los registros, así como que se realiza (y se onRestore()
llama) una restauración . Sin embargo, el archivo db en sí nunca se crea.
Tenga en cuenta que todo esto es 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 .
Tenga en cuenta también que no estoy hablando de una base de datos sqlite que administro yo mismo, ni de realizar copias de seguridad en una tarjeta SD, un servidor propio o en otro lugar.
Vi una mención en los documentos sobre las bases de datos que aconsejan usar una costumbre, BackupAgent
pero no parece estar relacionada:
Sin embargo, es posible que desee ampliar BackupAgent directamente si necesita: * Hacer una copia de seguridad de los datos en una base de datos. Si tiene una base de datos SQLite que desea restaurar cuando el usuario vuelva a instalar su aplicación, necesita crear un BackupAgent personalizado que lea los datos apropiados durante una operación de copia de seguridad, luego 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 me preocupan los siguientes temas:
Abrir bases de datos y transacciones. No tengo idea de cómo cerrarlos de una clase de singleton fuera del flujo de trabajo de mi aplicación.
Cómo notificar al usuario que se está realizando una copia de seguridad y la base de datos está bloqueada. Puede llevar mucho tiempo, por lo que es posible que deba 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 (y a ingresar datos en la base de datos). Por lo tanto, no puede presumir de restaurar los datos respaldados en su lugar (eliminando los datos vacíos o antiguos). Tendrá que unirse de alguna manera, lo que para cualquier base de datos no trivial es imposible debido a las identificaciones.
Cómo actualizar la aplicación después de que se realiza la restauración sin que el usuario se quede atascado en algún punto ahora inalcanzable.
¿Puedo estar seguro de que la base de datos ya se ha actualizado en la copia de seguridad o restauración? De lo contrario, es posible que el esquema esperado no coincida.
Respuestas:
Un enfoque más limpio sería crear un personalizado
BackupHelper
:public class DbBackupHelper extends FileBackupHelper { public DbBackupHelper(Context ctx, String dbName) { super(ctx, ctx.getDatabasePath(dbName).getAbsolutePath()); } }
y luego agréguelo a
BackupAgentHelper
:public void onCreate() { addHelper(DATABASE, new DbBackupHelper(this, DB.FILE)); }
fuente
Después de revisar mi pregunta, pude hacer que funcionara después de ver cómo lo hace ConnectBot . ¡Gracias Kenny y Jeffrey!
En realidad, es tan fácil como agregar:
FileBackupHelper hosts = new FileBackupHelper(this, "../databases/" + HostDatabase.DB_NAME); addHelper(HostDatabase.DB_NAME, hosts);
a tu
BackupAgentHelper
.El punto que me faltaba era el hecho de que tendrías que usar una ruta relativa con "
../databases/
".Aún así, esta no es de ninguna manera una solución perfecta. Los documentos para
FileBackupHelper
mencionar, por ejemplo: "FileBackupHelper
debe usarse solo con archivos de configuración pequeños, no archivos binarios grandes ", siendo este último el caso de las bases de datos SQLite.Me gustaría recibir más sugerencias, información sobre lo que se espera de nosotros (cuál es la solución adecuada) y consejos sobre cómo podría fallar.
fuente
db.open()
a travésdb.close()
o simplementeinsert
declaraciones o qué.Esta es una forma más limpia de hacer copias de seguridad de bases de datos como archivos. No hay rutas codificadas.
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 el directorio de bases de datos, no en el directorio de archivos.
Otra pista: también puede usar databaseList para obtener todos sus DB y nombres de fuentes de esta lista (sin la ruta principal) en FileBackupHelper. Entonces todas las bases de datos de la aplicación se guardarían en la copia de seguridad.
fuente
El uso
FileBackupHelper
para hacer una copia de seguridad / restaurar sqlite db plantea algunas preguntas serias:1. ¿Qué sucede si la aplicación usa el cursor recuperado
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 entrofia). Desinstala la aplicación, la vuelve a instalar y se restaura la copia de seguridad. Sin embargo, la vida puede ser brutal. Eche un vistazo al enlace . Imaginemos un escenario en el que un usuario compra un dispositivo nuevo. Como no tiene su propio conjunto, el agente de respaldo usa el conjunto de otro dispositivo. La aplicación está instalada y su backupHelper recupera el archivo antiguo con un esquema de versión db menor que el actual.
SQLiteOpenHelper
llamadasonDowngrade
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 haga el usuario, no puede usar su aplicación en el nuevo dispositivo.
Sugeriría usar
ContentResolver
para obtener datos -> serializar (sin_id
s) para respaldo y deserializar -> insertar datos para restaurar.Nota: la obtención / inserción de datos se realiza a través de ContentResolver, lo que evita problemas de moneda corriente. La serialización se realiza en su backupAgent. Si hace su propio mapeo de objetos cursor <->, serializar un elemento puede ser tan simple como implementar
Serializable
con eltransient
campo _id en la clase que representa su entidad.También usaría inserto a granel, es decir
ContentProviderOperation
ejemplo yCursorLoader.setUpdateThrottle
de manera que la aplicación no se ha quedado atascado con el reinicio del cargador de cambio de datos de copia de seguridad durante el proceso de restauración.Si se encuentra en una situación de degradación, puede optar por cancelar la restauración de datos 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 está bien explicado en los documentos y aún quedan algunas preguntas, como el tamaño de los datos masivos, etc.
Espero que esto ayude.
fuente
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 manera semántica directa: 'respaldar la base de datos llamada "mydata.db"'. Esta nueva API es mucho más fácil de usar para los desarrolladores: no tiene que realizar un seguimiento de las diferencias o solicitar un pase de respaldo explícitamente, y la descripción XML de qué archivos respaldar significa que a menudo no necesita escribir ningún código en absoluto.
(Usted puede involucrarse incluso en una copia de seguridad de todos los datos / operación de restauración para obtener una devolución de llamada cuando la restauración ocurre, por ejemplo. Es flexible de esa manera.)
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 usar la nueva API.
fuente
Una opción será construirlo en la lógica de la aplicación por encima de la base de datos. En realidad, creo que pide a gritos tal nivel. No estoy seguro de si ya lo está haciendo, pero la mayoría de las personas (a pesar del enfoque del cursor del administrador de contenido de Android) introducirán algunos mapeos ORM, ya sea personalizados o con un enfoque orm-lite. Y lo que preferiría hacer en este caso es:
Entonces, en este caso, en lugar de hacerlo a nivel de base de datos, hágalo a nivel de aplicación.
fuente