La manera más rápida y eficiente de pre-poblar la base de datos en Android

Si desea pre-poblar una base de datos (SQLite) en Android, esto no es tan fácil como uno podría pensar.

Así que he encontrado este tutorial que a menudo se hace referencia aquí en el desbordamiento de la pila también.

Pero realmente no me gusta esa forma de pre-poblar la base de datos ya que tomar el control del controlador de base de datos y crear los archivos usted mismo. Preferiría no tocar el sistema de archivos y dejar que el manejador de base de datos haga todo por sí mismo.

Así que lo que pensé que uno podría hacer es crear la base de datos en el controlador de base de datos onCreate () como de costumbre, pero luego cargar un archivo (.sql) de / assets que contiene las instrucciones para rellenar los valores:

INSERT INTO testTable (name, pet) VALUES ('Mike', 'Tiger'); INSERT INTO testTable (name, pet) VALUES ('Tom', 'Cat'); ... 

Pero llamar a execSQL () en onCreate () del manejador no funciona realmente. Parece que el archivo / assets no debe tener más de 1 MB y execSQL () sólo ejecuta la primera instrucción (Mike – Tiger).

¿Qué harías para pre-llenar la base de datos?

Sugiero lo siguiente:

  1. Envuelva toda su lógica INSERT en una transacción ( BEGIN... COMMIT o mediante las API beginTransaction () … endTransaction () )
  2. Como ya se sugirió, utilizar las API de enlace y reciclar objetos .
  3. No cree ningún índice hasta después de que este inserto masivo esté completo.

Además, echa un vistazo a los insertos masivos más rápidos en sqlite3?

Los estados de la pregunta, que desea la forma más rápida – pero no le gusta la forma en que se hace en el artículo – no desea reemplazar manualmente el archivo DB (aunque, puede ser realmente más rápido que rellenar DB vacío con Consultas).

Tenía exactlty los mismos pensamientos – y me di cuenta, que poblar a través de sentencias SQL y prepopulating puede ser la mejor solución – pero depende de la forma en que va a utilizar el DB.

En mi aplicación necesito tener cerca de 2600 filas (con 4 columnas) en DB en la primera ejecución – es los datos para el autocompletado y algunas otras cosas. Se modificará bastante rara vez (los usuarios pueden agregar registros personalizados, pero la mayoría de las veces – no es necesario) y es bastante grande. Suplantarla de las sentencias de SQL no sólo significa mucho más tiempo, sino más espacio en el APK (suponiendo que almacenaría datos dentro de él, como alternativa podría descargarlo desde Internet).

Este es el caso muy simple (el inserto "Big" puede tener lugar sólo una vez y sólo al inicio) y decidí ir con copiar un archivo de base de datos prepopulated. Claro, puede que no sea la mejor manera, pero es más rápido. Quiero que mis usuarios puedan usar la aplicación tan rápido como sea posible y tratar la velocidad como una prioridad – y realmente les gusta. Por el contrario, dudo que se alegraría cuando la aplicación se ralentizará porque pensé que la solución más lenta y mejor es realmente mejor.

Si en lugar de 2600 mi tabla tendría inicialmente ~ 50 filas, me iría con las sentencias de SQL, ya que la diferencia de velocidad y el tamaño no sería tan grande.

Usted tiene que decidir qué solución se ajusta mejor a su caso. Si prevé cualquier problema que pueda surgir del uso de "prepopulated db" opción – no lo utilizan. Si no está seguro acerca de estos problemas, pregunte, proporcionando más detalles sobre cómo utilizará (y eventualmente, actualizará) los contenidos de la base de datos. Si no está muy seguro de qué solución será más rápida – compararlo. Y no tenga miedo de que el método de archivo de copia – que puede funcionar muy bien, si se utiliza sabiamente.

Usted puede tener su pastel y comerlo también. Aquí hay una solución que puede respetar el uso de su adaptador db y también usar un proceso de copia simple (y mucho más rápido) para una base de datos pre-poblada.

Estoy usando un adaptador db basado en uno de los ejemplos de Google. Incluye una clase interna dbHelper () que extiende la clase SQLiteOpenHelper () de Android. El truco es anular su método onCreate (). Este método sólo se llama cuando el ayudante no puede encontrar el DB que está haciendo referencia y tiene que crear el DB para usted. Esto sólo debería ocurrir la primera vez que se llame a cualquier instalación de dispositivo dada, que es la única vez que desea copiar la base de datos. Así que anularlo como este –

  @Override public void onCreate(SQLiteDatabase db) { mNeedToCopyDb = true; } 

Por supuesto, asegúrese de haber declarado e inicializado este flag en el DbHelper –

  private Boolean mNeedToCopyDb = false; 

Ahora, en el método open () de su dbAdapter, puede probar si necesita copiar el DB. Si lo hace, cierre el ayudante, copie el DB y finalmente abra un nuevo ayudante (consulte el código a continuación). Todos los futuros intentos de abrir el db utilizando el adaptador db encontrarán su base de datos (copiada) y por lo tanto el método onCreate () de la clase DbHelper interna no será llamado y el indicador mNeedToCopyDb permanecerá falso.

  /** * Open the database using the adapter. If it cannot be opened, try to * create a new instance of the database. If it cannot be created, * throw an exception to signal the failure. * * @return this (self reference, allowing this to be chained in an * initialization call) * @throws SQLException if the database could neither be opened nor created */ public MyDbAdapter open() throws SQLException { mDbHelper = new DatabaseHelper(mCtx); mDb = mDbHelper.getReadableDatabase(); if (mDbHelper.mNeedToCopyDb == true){ mDbHelper.close(); try { copyDatabase(); } catch (IOException e) { e.printStackTrace(); } finally { mDbHelper = new DatabaseHelper(mCtx); mDb = mDbHelper.getReadableDatabase(); } } return this; } 

Simplemente coloque algún código para hacer la copia de su base de datos dentro de su adaptador db en un método denominado copyDatabase () como se utiliza anteriormente. Puede utilizar el valor de mDb que fue actualizado por la primera instancia de DbHelper (cuando creó el DB de stub) para obtener la ruta de acceso a utilizar para su flujo de salida cuando realiza la copia. Construya su flujo de entrada como este

 dbInputStream = mCtx.getResources().openRawResource(R.raw.mydatabase); 

[Nota: Si su archivo de DB es demasiado grande para copiar en un trago y luego dividirlo en algunas piezas.]

Esto funciona muy rápido y pone todo el código de acceso db (incluyendo la copia del DB si es necesario) en su adaptador db.

Escribí una clase de DbUtils similar a la respuesta anterior. Es parte de la herramienta ORM greenDAO y está disponible en github . La diferencia es que intentará encontrar los límites de la declaración usando una expresión regular simple, no sólo terminaciones de línea. Si tienes que confiar en un archivo SQL, dudo que haya una forma más rápida.

Pero, si puede proporcionar los datos en otro formato, debe ser significativamente más rápido que usar una secuencia de comandos SQL. El truco es usar una instrucción compilada . Para cada fila de datos, enlaza los valores analizados a la sentencia y ejecuta la instrucción. Y, por supuesto, usted necesita hacer esto dentro de una transacción. Yo recomendaría un formato de archivo separado delimitador simple (por ejemplo, CSV), ya que puede ser analizada más rápido que XML o JSON.

Hicimos algunas pruebas de rendimiento para greenDAO. Para nuestros datos de prueba, tuvimos tasas de inserción de alrededor de 5000 filas por segundo. Y por alguna razón, la tasa bajó a la mitad con Android 4.0 .

Ye, los activos tal vez tiene límite de tamaño, por lo que si es más grande que el límite, puede cortar a más archivos.

Y exesql soporte más oración sql, aquí te da un ejemplo:

  BufferedReader br = null; try { br = new BufferedReader(new InputStreamReader(asManager.open(INIT_FILE)), 1024 * 4); String line = null; db.beginTransaction(); while ((line = br.readLine()) != null) { db.execSQL(line); } db.setTransactionSuccessful(); } catch (IOException e) { FLog.e(LOG_TAG, "read database init file error"); } finally { db.endTransaction(); if (br != null) { try { br.close(); } catch (IOException e) { FLog.e(LOG_TAG, "buffer reader close error"); } } } 

Encima del ejemplo requieren la necesidad de INIT_FILE que cada línea es una oración del sql .

Además, si el archivo de frases de sql es grande, puede crear la base de datos en el sitio de android (soporte sqlite para windows, linux, para que pueda crear la base de datos en su os y copiar el archivo de base de datos a su carpeta de activos, Se puede cerrar)

Cuando se ejecuta la aplicación, puede obtener el archivo de base de datos de los activos, dirigido a guardar en la carpeta de la base de datos de la aplicación (si se cierra, puede descomprimir a la carpeta de la base de datos de la aplicación)

La esperanza puede ayudarte

Utilicé este método. Primero crear su base de datos sqlite hay algunos programas que puede utilizar me gusta SqliteBrowser . A continuación, copie el archivo de base de datos en su carpeta de activos. A continuación, puede utilizar este código en el constructor de SQLiteOpenHelper.

 final String outFileName = DB_PATH + NAME; if(! new File(outFileName).exists()){ this.getWritableDatabase().close(); //Open your local db as the input stream final InputStream myInput = ctx.getAssets().open(NAME, Context.MODE_PRIVATE); //Open the empty db as the output stream final OutputStream myOutput = new FileOutputStream(outFileName); //final FileOutputStream myOutput = context.openFileOutput(outFileName, Context.MODE_PRIVATE); //transfer bytes from the inputfile to the outputfile final byte[] buffer = new byte[1024]; int length; while ((length = myInput.read(buffer))>0){ myOutput.write(buffer, 0, length); } //Close the streams myOutput.flush(); ((FileOutputStream) myOutput).getFD().sync(); myOutput.close(); myInput.close(); } } catch (final Exception e) { // TODO: handle exception } 

DB_PATH es algo así como /data/data/com.mypackage.myapp/databases/

NAME es cualquier nombre de base de datos que elija "mydatabase.db"

Sé que hay muchas mejoras en este código, pero funcionó tan bien y es muy rápido. Así que lo dejé solo. Como esto podría ser aún mejor en el método onCreate (). También comprobar si el archivo existe cada vez probablemente no es el mejor. De todos modos como he dicho que funciona, es rápido y fiable.

Si los datos no son privados, entonces simplemente alojar en su sitio web, a continuación, descargar en primera ejecución. De esa manera usted puede mantenerlo al día. Siempre que recuerdes tener en cuenta la versión de la aplicación cuando la subas a tu servidor web.

  • Problemas para obtener Calendar.WEEK_OF_YEAR
  • ¿Cómo eliminar la base de datos del emulador?
  • Java.lang.StackOverflowError
  • SQLite de Android Cursor fuera de límites de excepción en SELECT count (*) FROM table
  • Tabla de actualización de Android sqlite siempre devuelve 0
  • ¿Es posible hacer una consulta sin procesar en la base de datos de metales de Android de meta sqlite?
  • El ejemplo de NotesDbAdapter es para una tabla, ¿qué hay de varias tablas?
  • Android cadena de escape real en sqlite
  • No se pueden actualizar varias filas en el comando de actualización de la base de datos Sqlite en android
  • ¿Qué hace exactamente la restricción de clave externa "NO ACTION" de SQLite y cómo es diferente de "RESTRICT"?
  • Cómo insertar marca de tiempo en una columna de base de datos SQLite? Utilizando el tiempo de función ('ahora')?
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.