Android: copia la base de datos de la carpeta de activos, pero sólo obtiene un archivo vacío
Chicos, tengo el problema al copiar la base de datos de la carpeta de activos locales a / data / data / package_name / directorio de bases de datos. Como uso el http://www.reigndesign.com/blog/using-your-own-sqlite-database-in-android-applications/ tutorial para hacerlo, sólo puedo obtener un archivo vacío.
He citado la parte del método copyDataBase () y no hay diferencia. Cada vez que se inicie la aplicación, creará el directorio y la base de datos vacía. Entonces, ¿hay alguna manera de hacer que copyDataBase () funcione?
- Android DataBase está bloqueado por otro hilo
- ¿Cómo almacena una colección de cadenas en SQLite en Android?
- ¿Cómo recuperar datos de un cursor en android?
- Copia de seguridad de Android y restauración de la base de datos desde y hacia la tarjeta SD
- Android sqlite: cómo recuperar datos específicos de la columna en particular?
¡¡Muchas gracias!!
- Cómo probar la actualización de la base de datos sqlite antes de cargar la nueva versión de mi aplicación en la tienda de juegos en android
- Insertar datetime en la base de datos sqlite android
- Tabla de puntuaciones altas
- SQLite - ¿Es posible insertar un BLOB a través de la instrucción insert?
- Java.lang.illegalstateexception no abre la base de datos android
- IllegalArgumentException: columna no válida
- El comodín no funciona en SQLite
- Cómo implementar herencia de tabla en GreenDao
No copiaría ningún formulario de base de datos de la carpeta de Si necesita alguna entrada estándar en su base de datos, puede agregarla utilizando assets
.INSERT
s en su método onCreate()
.
Actualización: Puesto que esto es conseguir abajo votado por estar equivocado (que es un poco correcto) y no puedo eliminarlo, aquí hay una pequeña actualización.
Yo diría que depende de cuántas entradas estándar que desea agregar a su base de datos. Si es sólo uno o dos, el envío de un paquete de DB podría no valer la pena.
De todas formas, algunas aplicaciones vienen con bases de datos bastante grandes (por ejemplo, una colección de recetas). Obviamente, no puede agregar todos estos en el código.
- Para pequeñas entradas de prueba, todavía preferiría simplemente agregarlas en
onCreate()
. - Para bases de datos más grandes, debe pre-poblarlas y enviar em junto con su aplicación.
Para que funcione más tarde, tendrá que copiar el archivo de base de datos de assets/
a su carpeta de aplicaciones. Hay una bonita biblioteca para manejar eso para ti: android-sqlite-asset-helper
¿Por qué no copia de los activos? Es perfectamente normal hacerlo. Pero no se puede hacer en el onCreate, en ese momento ya se ha creado una base de datos vacía. Tienes que hacerlo antes. Normalmente lo hago en una anulación de getWriteableDatabase, algo así como
public synchronized SQLiteDatabase getWritableDatabase() { SQLiteDatabase db = null; if (!doesDatabaseExist()) { try { copyDatabase(); db = super.getWritableDatabase(); } catch(Exception ex) { Log.e("Database Log", getDatabasePath() + " failed to copy correctly. " + ex.getLocalizedMessage()); } } else { db = super.getWritableDatabase(); } return db; }
A la derecha encima del ejemplo trabajó para mí de esta manera:
db = super.getWritableDatabase(); db.close; copyDatabase();
De lo contrario tengo un error de E / S;
Aquí está el código simple y conveniente que utilizo:
public class DataBaseImportHelper { private DataBaseImportHelper() {}; // Avoid instantiation /** * Creates a empty database on the system and rewrites it with your own database. */ public static boolean importDataBase(Context context) { InputStream myInput = null; OutputStream myOutput = null; try { // Open local db from assets as the input stream myInput = context.getAssets().open(DATABASE_NAME); createEmptyDatabase(context); // See this method below // Open the empty db as the output stream myOutput = new FileOutputStream(getDatabaseFile(context)); // transfer bytes from the inputfile to the outputfile byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer)) > 0) { myOutput.write(buffer, 0, length); } // Close the streams myOutput.flush(); myInput.close(); myOutput.close(); return true; } catch (IOException e) { e.printStackTrace(); } return false; } /** * Check if the database already exists. * @return true if it exists, false if it doesn't */ public static boolean isDatabaseExists(Context context) { return getDatabaseFile(context).exists(); } private static File getDatabaseFile(Context context) { return context.getDatabasePath(DatabaseHelper.DATABASE_NAME); } /** * Create an empty database into the default application database * folder.So we are gonna be able to overwrite that database with our database */ private static void createEmptyDatabase(Context context) { // use anonimous helper to create empty database new SQLiteOpenHelper(context, DatabaseHelper.DATABASE_NAME, null, 1) { // Methods are empty. We don`t need to override them @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } @Override public void onCreate(SQLiteDatabase db) { } }.getReadableDatabase().close(); }
}
Y usando en código:
if(!DataBaseImportHelper.isDatabaseExists(this)){ if (!DataBaseImportHelper.importDataBase(this)){ throw new IllegalStateException("Database doesn`t exist and hasn`t been copied!"); } }
No sé si todavía es útil, pero aquí es la solución para otros que llegan aquí para ver el awnser. El código que usó, funciona para la mayoría de los teléfonos, algunos teléfonos antiguos tienen un comportamiento diferente con la función getReadableDatabase (). Por lo tanto, su problema no está en la función copyDataBase sino en la función createDataBase.
En createDataBase () hay la siguiente comprobación;
this.getReadableDatabase();
Esto comprueba si ya existe una base de datos con el nombre proporcionado y si no crea una base de datos vacía tal que se puede sobrescribir con la de la carpeta de activos. En los dispositivos más nuevos esto funciona sin problemas, pero hay algunos dispositivos en los que esto no funciona. Principalmente los dispositivos más antiguos. No sé exactamente por qué, pero parece que la función getReadableDatabase () no sólo recibe la base de datos sino que también la abre. Si a continuación, copiar la base de datos de la carpeta de activos sobre ella, todavía tiene el puntero a una base de datos vacía y obtendrá tabla no existen errores.
Así que para que funcione en todos los dispositivos, debes modificarlo a las siguientes líneas:
SQLiteDatabase db = this.getReadableDatabase(); if (db.isOpen()){ db.close(); }
Incluso si la base de datos se abre en el cheque, se cierra a partir de entonces y no le dará más problemas.
- Marcación de mensajes SMS como mensajes de lectura / no leídos o eliminación de mensajes que no funcionan en KitKat
- Twitter Fabric + MultiDex causa NoClassDefFoundError