Cuando se busca documentación sobre bases de datos en Android, siempre nos encontramos con montones de ejemplos en los que se nos indica cómo crear una base de datos programáticamente, cómo introducir datos en ella, como extraerlas para obtener un objeto Cursor, etc. Entre estos me gusta destacar los siguientes: el fabuloso blog de sgoliver (varias partes), la guía oficial de developers de Android o el excelente tutorial de AndroidHive.

Sin embargo, es más complicado encontrar información sobre cómo importar una base de datos cuando ya la tenemos creada externamente y la queremos usar en nuestra app. Pues aquí va este minitutorial.

Esto no es ni la guía definitiva ni, posiblemente, el método más eficiente pero es el mío y a mi me funciona.

Para empezar, necesitamos una herramienta para crear estas bases de datos, yo uso dos: SQLite Database Browser y Excel. ¿Por qué? Pues porque Excel es una herramienta súper eficaz y rápida de crear tablas además de que todo el mundo se maneja más o menos con ella lo que permite un trabajo distribuido. Por otro lado, SQLite Database Browser es una herramienta con licencia GPL, ligera, que no necesita instalación y que maneja con soltura bases de datos amplias. Además dispone de extensión para Firefox, que más se puede pedir.

Entonces, dividiremos esto en dos pasos, cómo creo las bases de datos y como las importo para usar en Android

CREACIÓN DE LA BASE DE DATOS

Esto no tiene mucho misterio, uso Excel para crear la tabla de datos y la guardo como archivo CSV (en guardar como -> tipo de archivo podréis escoger esta opción).

Y ahora uso SQLite Database Browser para importar esta tabla CSV y crear una base de datos SQLite que será utilizable por mi app Android.

Abrimos SQLite DB Browser y creamos una base de datos en blanco, simplemente ponemos el nombre del archivo, de momento no incorporamos ningún campo a mayores (tampoco hace falta ponerle nombre a la tabla aunque aparezca en la imagen) por tanto le dais a cancelar. Observaréis que en la barra de la ventana de la aplicación os aparece la ruta de vuestra base de datos, esto significa que tenéis creado el archivo pero todavía no contiene ninguna tabla:

CrearlaTabla

A continuación importamos los datos: File – Import – Table from CSV File. Seleccionáis vuestra tabla CSV y os deberían aparecer los datos en el cuadro en blanco de la parte inferior:

ImportarDatosy ahora sí, rellenáis el nombre de la tabla, escogéis el carácter separador de datos (en este caso veis que es un «;» ) y, si en la primera fila habéis puesto nombre a la columna, podéis indicarle que extraiga de ahí los nombres de los campos.

IMPORTANTE: Al seleccionar el archivo os deberían salir inmediatamente los datos en la ventana. Si no fuera así está habiendo algún problema con la importación. Comprobad que tenéis el archivo Excel CSV cerrado ya que de lo contrario no podrá importar los datos.

Pues ya podéis crear vuestra tabla. Ahora lo ideal es incluir un id en esta tabla (requisito esencial para un correcto indexado de las tablas SQLite) y darle detalles al archivo sobre lo que contiene cada celda. Así que en la pestaña Browse Data – Edit – Modify Table y seleccionáis la tabla que acabáis de crear.

Yo lo primero que hago es crear un nuevo campo (Add field) que será el identificador de columna que se emplea en las tablas SQLite:

ModificandoLaTablaA continuación, para el resto de los campos, con Edit field vamos poniendo los nombre y el tipo de campo.

Hecho esto tenéis vuestra tabla creada. Como veis el programa os permite hacer consultas de comandos SQL, en la pestaña «Execute SQL» para hacer cualquier tipo de comprobación.

USAR NUESTRA BASE DE DATOS EN ANDROID

Para usar esta BD en nuestra app tendremos que tenerla en el directorio assets de nuestra app pero esto no es suficiente. Esto es un recurso pero para poder usarlo, hemos de crear una base de datos en blanco programáticamente y copiar la base de datos alojada en assets sobre la base de datos en blanco.

[[Todo esto evidentemente requiere que conozcáis cómo se manejan bases de datos, crear la clase DBHelper, que hereda de SQLiteOpenHelper, etc. Leed los tutoriales que os indiqué más arriba si necesitáis refrescar estos puntos]]

Os pongo el código de mi proceso (cada uno puede mejorarlo en su aplicación!!):

1. En el Main.java, abrimos / creamos la DB en onCreate():


try {
dbHelper.openDB();  // Llamamos a la función openDB() de nuestra clase DBHelper
} catch (SQLiteException e) {
Log.e("DB_Opening", "Error opening databases");
dbHelper.closeDB();
}

2. En el método onPause() yo siempre cierro la BD para no dejar recursos abiertos cuando se pasa a otra actividad o aplicación, así que:


public void onPause() {
super.onPause();
dbHelper.closeDB();  //Llamamos a closeDB() de nuestra clase DBHelper
}

3. Dentro de la propia clase DBHelper, tenemos las siguientes funciones:

3.1. openDB() para abrir la base de datos:


public void openDB() throws SQLiteException
{
createDataBase();
String path = mContext.getDatabasePath(DB_NAME).getAbsolutePath();
mDataBase = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.NO_LOCALIZED_COLLATORS);
}

Así, primero llamamos a la función createDataBase(), esta función (a continuación) comprueba si ya existe la base de datos, si no existe la crea. A continuación guardamos el path en el que se encuentra la DB (siendo DB_NAME una constante dónde guardo el nombre de la DB). Finalmente, teniendo el path, llamo a la función openDatabase para tener una referencia a la base de datos.

Es importante que realicéis un correcto manejo de las excepciones para saber dónde pueda fallar el programa y para que no tengamos un uncaughtException.

3.2. createDataBase() para crear la base de datos (comprueba previamente si existe):


public void createDataBase() throws SQLiteException
{
if (checkDataBase() == false)
{
SQLiteDatabase sq = this.getWritableDatabase();
try{
copyDataBase(DB_PATH);
}catch (IOException e){
show ("createDataBase: Error while copying the DB");
}finally{
sq.close();
}
}
}

Como véis primero compruebo si existe la base de datos con checkDataBase() (a continuación). Si no existe (devuelve false), creamos una vacía en modo escritura para poder escribir por encima. Una vez creada, copiamos la BD que hemos creado fuera del programa (en el paso 1 de este post) sobre la BD en blanco recién creada, llamando a copyDataBase().

3.3. checkDataBase() comprueba si la BD interna existe (no la de assets, eso es un recurso, las bases de datos en android se guardan en data/data/packageName/databases).


public boolean checkDataBase()
{
File fileDB = null;
fileDB = mContext.getApplicationContext().getDatabasePath(DB_NAME);
boolean checkDB = fileDB.exists();
return (checkDB);
}

Para comprobar si existe la BD, simplemente tratamos de obtener una referencia a ella en el directorio dónde estaría guardada. Fácil.

Y a partir de aquí todo es java estándar. Tenemos que copiar una base de datos sobre la otra (la función que ponía arriba copyDataBase()) que no incluyo porque el post se hace largo y porque no tiene nada especial. Abrimos un flujo de entrada desde la BD de assets y un flujo de salida hacia la BD en blanco que acabo de crear para copiar una sobre la otra. Y listo, ya podemos usar nuestra BD externa en android.

Conclusión: parece un poco complicado esto de usar bases de datos externas pero claro, crear una base de datos dentro de la aplicación es impracticable en muchas situaciones. No hay más remedio que llevar el archivo en assets y SÍ, duplicarlo internamente para poder usarlo. Ya que assets es un directorio que se compila con el apk, no hay manera de borrar esta BD que ya no necesitaremos después de copiarla en el directorio interno. Así es la vida android.

En cualquier caso, si quisiéramos en un futuro poder actualizar la BD interna con otra BD nueva que descarguemos a assets, deberíamos llevar un control de versiones pero el proceso sería el mismo, copiar por encima y listo o, si la base de datos es muy grande, aprovechar los comandos SQL para copiar los datos no duplicados de la BD nueva en la BD antigua.

Por favor, si alguien conoce un método nuevo para poder trabajar con BD externas, yo estaré encantando de escucharle.

Nos leemos 😉