Programación Android, Base de Datos II

Share if you like...Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0

Android SQLite

Como dijimos en la entrada anterior, en Android se utilizan bases de datos SQLite, aprovechando que es un sistema muy ligero y que ofrece la suficiente potencia para poder controlar todos los datos que necesitemos en nuestras aplicaciones.

En esta entrada vamos a crear la clase de nuestro proyecto que se va a encargar de controlar la Base de Datos de la aplicación, y mostraremos las variables que son obligatorias, así como los métodos utilizados para crear la Base de Datos y la tabla, o las tablas si se utilizarán varias, en la que almacenar los datos. En el ejemplo que vamos a poner a continuación utilizaremos una única tabla, para simplificar la explicación y que quede más clara. Sin embargo más adelante haremos otro ejemplo con el que trabajar con diferentes tablas, utilizando la Programación Orientada a Objetos para que nuestro código quede más claro.

Creando la clase Adaptador de la Base de Datos

En primer lugar debemos crear una nueva clase, que llamaremos DBAdapter (el nombre no es obligatorio, pero siempre es conveniente utilizar un nombre que deje claro para qué sirve la clase), y va a contener las siguientes variables obligatoriamente:

private final static int DB_VERSION = 1;
private final static String DB_NAME = "nombreDB";
private final static String TB_NAME = "nombreTabla";

Estos valores indican:

  • DB_VERSION: Versión de la base de datos que estamos utilizando. Se utiliza para cuando se realizan actualizaciones en la estructura de la BD, hará que automáticamente se actualice la BD del dispositivo al actualizar la aplicación. Más adelante indicaremos cómo sucede esto con más detalle.
  • DB_NAME: Nombre de la BD, si nuestra BD se llamará dbUsers, por ejemplo, ese será el valor que indiquemos en el String.
  • TB_NAME: Nombre de la tabla que contendrá la BD. Al igual que con el nombre de la BD, el valor del String será el nombre de la tabla que queramos. Esta variable conviene no llamarla exactamente así, ya que podemos contener varias tablas en nuestra BD, por lo que es conveniente nombrar la variable de forma que haga referencia al nombre de la tabla.

Creando la clase interna BaseColumns

Una vez que tenemos la información de la BD definida, tenemos que indicar los campos que contendrá la tabla que vamos a utilizar, para hacer esto vamos a crear una clase interna, que va a implementar la interfaz BaseColumns. Esta clase nos va a ayudar a acceder a los campos de la tabla desde el código de manera más cómoda, más adelante en nuestra aplicación:

private class Columns implements BaseColumns {
	public final static String ID = "_id";
	public final static String CAMPO1 = "campo1";
	public final static String CAMPO2 = "campo2";
	public final static String CAMPO3 = "campo3";
	// ...
}

Lo primero que vemos en el código es una clase privada, esto es así porque realmente a estos datos no tiene por qué tener que acceder ninguna otra clase, ya que son datos que tienen que ver con la tabla de la BD, y únicamente la clase DBAdapter debe tener acceso a cualquier información que esté relacionada con la BD (de manera que respetemos el MVC del que hablamos en la entrada anterior).

Después vemos una lista de variables estáticas y públicas, son públicas porque es necesario poder acceder desde fuera de la clase a estas variables, ya que DBAdapter va a hacer uso de ellas. Si las marcáramos como privadas sería imposible que DBAdapter pudiera acceder a ellas, ya que sólo serían visibles por la propia clase Columns. Dentro del listado de variables, llama la atención la primera de ellas. Realmente este será un campo de la nuestra tabla, y es OBLIGATORIO para todas las tablas que creemos en nuestras bases de datos. Este campo es un campo que internamente utiliza Android para poder recorrer las tablas, y además será de tipo integer, autoincrement y la primary key de la tabla. Después de este primer campo ID obligatorio, declararemos tantas variables como campos contenga nuestra tabla.

Este dato puede hacernos cambiar la estructura de las tablas que inicialmente tuvieramos planteada, ya que es posible que nuestra tabla fuera a almacenar DNI y nombre de personas, y por lo tanto el campo DNI fuera nuestra PK (primary key). Sin embargo en Android no nos es posible hacerlo así, porque la PK va a ser el campo _id. Eso lo solucionaremos convirtiendo las PKs de nuestras tablas en claves unique (para más información sobre la sintaxis visiten sqlite.org). En futuros ejeplos veremos con más detenimiento también cómo utilizar estos datos, de momento vamos a seguir con el ejemplo sin campos unique para que los conceptos básicos sigan quedando claros.

Una vez que tenemos definida esta clase, crearemos otra variable más, un array de Strings, que va a contener todas los valores de las variables que hemos creado en nuestra clase Columns. Esta nueva variable la utilizaremos en algunos métodos para leer los datos de la tabla:

private final static String[] COLUMNS = { Columns.ID, Columns.CAMPO1,
		Columns.CAMPO2, Columns.CAMPO3 };

A continuación crearemos una nueva variable, que será la que contenga la sentencia sql de creación de nuestra tabla. Una sentencia genérica sería:

private final static String CR_TABLE = "create table if not exists "
		+ TB_NAME + "(" + Columns.ID
		+ " integer autoincrement primary key, " + Columns.CAMPO1
		+ " text not null, " + Columns.CAMPO2 + " text, " + Columns.CAMPO3
		+ " integer)";

Fijémonos que al escribir la sentencia hemos escrito exactamente una sentencia que utilizaríamos en consola para crear la tabla, atendiendo a las reglas de sintaxis SQLite. Sin embargo no hemos añadido el “;” de final de sentencia. Este “;” no lo vamos a poner nunca cuando escribamos sentencias directamente en nuestro código, ya que esto se gestionará internamente sin necesidad de ponerlo nosotros.

Creando la clase interna SQLiteOpenHelper

Y ya por último crearemos una nueva clase interna, que será la que va a darnos el canal de comunicación directamente con nuestra base de datos. Esta nueva clase va a heredar de la clase SQLiteOpenHelper, que es la que Android nos facilita para gestionar nuestras bases de datos, y a su vez nos obligará a escribir un constructor específico y a sobreescribir dos métodos que explicaremos a continuación:

private class DBHelper extends SQLiteOpenHelper {

	public DBHelper(Context context, String name, CursorFactory factory,
			int version) {
		super(context, name, factory, version);
		// TODO Auto-generated constructor stub
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		// TODO Auto-generated method stub

	}
}

Expliquemos paso a paso. Primero tenemos un constructor de nuestra clase DBHelper, que necesita un Context, un String, un CursorFactory y una int que corresponderá a la versión.

El primero de los valores aún lo tenemos que conseguir de alguna parte, pues no existe en nuestra clase DBAdapter. Veremos más adelante cómo lo hacemos.

El segundo valor es el nombre de nuestra BD, que ya lo tenemos en nuestra clase BDAdapter y es una variable accesible por esta clase interna, por la que podremos eliminarla del constructor, y mandarla directamente al super (llamada al constructor de la clase base SQLiteOpenHelper).

El tercer valor no es necesario para nosotros, en realidad esta variable se utiliza en casos en que utilicemos cursores que nosotros creemos que implementen determinadas operaciones adicionales, como este no es nuestro caso pasaremos null, por lo que también podemos eliminar esta variable del constructor y pasarle el null al super.

El tercer valor es la versión de nuestra BD, en este punto es en el que automáticamente Android controla si ha habido algún cambio en la BD, pues si hemos aumentado la versión de la BD, por haber realizado cambios en su estructura, aquí es donde Android se dará cuenta y comenzará el proceso de actualización de dicha estructura. Este parámetro también lo tenemos en nuestra clase DBAdapter, por lo que lo podremos eliminar del constructor también.

Creando el constructor de SQLiteOpenHelper

Una vez realizados los cambios en nuestro constructor, quedaría así:

public DBHelper(Context context) {
	super(context, DB_NAME, null, DB_VERSION);
}

Sobreescribiendo los métodos de SQLiteOpenHelper

A continuación nos encontramos con los dos métodos que hemos sobreescrito. El primero de ellos es el método onCreate. Este método es el que se va a ejecutar cuando se ejecute la aplicación y no esté creada la BD (por ejemplo cuando se instale la aplicación por primera vez), por lo tanto tendremos que indicarle que cree todas las tablas que vaya a contener nuestra BD. Para ello haremos uso de la variable SQLiteDatabase que nos viene como parámetro en el método, y utilizaremos el método execSQL(), que nos permite indicar, en una de sus sobrecargas, únicamente una sentencia SQLite para que se ejecute. Como parámetro le pasaremos la variable CR_TABLE que definimos con la sentencia de creación de nuestra tabla:

@Override
public void onCreate(SQLiteDatabase db) {
	db.execSQL(CR_TABLE);
}

Y por último queda el método onUpgrade. Este método se lanza automáticamente cuando Android determina que se ha realizado una actualización de la versión de nuestra BD, y será el encargado de actualizar toda la estructura. Para ello en primer lugar tendríamos que recoger toda la información de las tablas que tengamos, después actualizar tablas y por último volver a escribir toda la información, de manera que no tuviéramos ninguna pérdida. Sin embargo en este ejemplo vamos a simplificarlo y simplemente borraremos tablas y volveremos a crearlas:

@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
	db.execSQL("drop table if exists " + TB_NAME);
	onCreate(db);   // Llamamos al método onCreate para volver a crear
			// las tablas.
}

En primer lugar borramos cada una de las tablas que contenga nuestra BD (en este ejemplo una), y después haremos llamada al método onCreate y le pasarémos la variable SQLiteDatabase que nos viene como parámetro también en onUpgrade para que se creen todas las tablas de nuestra DB.

Creando el constructor de DBAdapter

Y por último sólo nos falta crear nuestro constructor, que va a necesitar un único parámetro, el Context que necesitábamos para la creación de la BD, que directamente inicializará una variable de tipo DBHelper que declararemos en la clase DBAdapter:

DBHelper dbHelper;

public DBAdapter(Context context) {
	dbHelper = new DBHelper(context);
}

Esta variable DBHelper será la que nos ayudará a inicializar la variable SQLiteOpenHelper, que a su vez será la que nos permita manipular la BD desde nuestra aplicación.

Resultado del código de la clase DBAdapter

Con esto nuestra clase completa quedaría así:

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBAdapter {
	private final static int DB_VERSION = 1;
	private final static String DB_NAME = "nombreDB";
	private final static String TB_NAME = "nombreTabla";

	private class Columns implements BaseColumns {
		public final static String ID = "_id";
		public final static String CAMPO1 = "campo1";
		public final static String CAMPO2 = "campo2";
		public final static String CAMPO3 = "campo3";
		// ...
	}

	private final static String CR_TABLE = "create table if not exists "
			+ TB_NAME + "(" + Columns.ID
			+ " integer autoincrement primary key, " + Columns.CAMPO1
			+ " text not null, " + Columns.CAMPO2 + " text, " + Columns.CAMPO3
			+ " integer)";

	private DBHelper dbHelper;

	public DBAdapter(Context context) {
		dbHelper = new DBHelper(context);
	}

	private class DBHelper extends SQLiteOpenHelper {

		public DBHelper(Context context) {
			super(context, DB_NAME, null, DB_VERSION);
		}

		@Override
		public void onCreate(SQLiteDatabase db) {
			db.execSQL(CR_TABLE);

		}

		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
			db.execSQL("drop table if exists " + TB_NAME);
			onCreate(db);
		}
	}
}

Lo último que queda por ver es cómo escribir, leer y modificar datos de nuestra BD y cómo haremos uso de esta clase para poder acceder a todos estos métodos desde nuestra aplicación. Lo podremos ver en la próxima entrada.

Share if you like...Share on Facebook0Tweet about this on TwitterShare on Google+0Share on LinkedIn0
The following two tabs change content below.
Reborn as IT Developer. Desarrollador Android y fundador de Proyecto Simio. "En realidad, yo no puedo enseñar nada a nadie, sólo puedo hacerles pensar." - Sócrates.

11 thoughts on “Programación Android, Base de Datos II

  1. Amigo excelente explicacion, te felicito realmente por tu gran labor de compartir tu conocimiento lo mas explicito posible. quiero preguntarte algo, si necesito crear varias tablas, ¿debo crear varias clases internas que implementen BaseColumns? porque no se me ocurre otra manera de crear varias tablas para mi BD.

      1. Ok ya entendi. pero solo me queda una duda mas. en el metodo onupgrade, si tengo una base de datos con varias tablas y yo en ese metodo realizo:
        db.execSQL(“drop table if exists ” + nombre de la tabla) esta instruccion para mis cuatro tablas y al final ejecuto el metodo oncreate(db). se perderian todos los registros que ya han sido creados en la BD??. si es asi entonces que deberia utilizar en el metodo onupgrade() para no perder la informacion, ya que estoy haciendo una aplicacion para la materia de la universidad.
        Nuevamente te doy las gracias por tu gran aporte

        1. Efectivamente, como en cualquier base de datos si haces un drop table eliminas todos los datos que pueda contener, por eso en la explicación de este método digo que hay que recoger los datos, actualizar las tablas y volver a añadir los datos a las tablas.

          Muchas gracias por tu comentario :)

          Un saludo.

  2. Hola

    soy nuevo en Android y quisiera me ayudaran a aclarar algo.
    como tendria que hacer, sino deseo crear una base de datos nueva, por que ya la tengo creada. Solo quiero integrarla a mi proyecto y utilizarla para leer datos de ella y/o actualizarla.
    si me podrian ayudar con un ejemplo.. Gracias

    1. Nunca he tenido que hacer algo parecido, y no puedo asegurar nada, pero no creo que puedas hacer eso. En el caso de poder tendrías que investigar cómo se hace en un proyecto de una aplicación Java de escritorio, y comprobar si puedes hacer lo mismo en el proyecto Android, pero, como te digo, me da la sensación de que no puedes añadir una base de datos externa a la aplicación.

      Lo único que se me ocurre es que trabajes con una base de datos en un servidor, y todos los datos los trabajes atacando al servidor en lugar de usar una base de datos local.

      Un saludo y suerte.

      1. Hola

        gracias por tu respuesta. En realidad era una duda que tenia, ya que los tutoriales que veo, en todos crean la base de datos siempre. Y queria aclararlo.
        Ya que tambien habia visto en tutoriales para Eclipse que copiaban una base de datos en una carpeta llamada Assets. Y luego la accedian, sin embargo estoy utilizando Android Studio para mi proyecto.

        saludos,

  3. tengo una duda con respecto a las bases de datos en android….
    quería saber si android permite que una aplicación utilice más de una base de datos

    1. Buenas Andrés.

      Nunca he tenido que hacer la prueba, pero en principio sí sería posible. Tendrías que modificar el constructor de la clase que extiende de SQLiteOpenHelper (en comparación con el ejemplo que yo utilizo) para que además del Context también reciba el nombre de la base de datos y la versión en sus parámetros. Después en la clase que gestione la conexión a la base de datos (en mi ejemplo DBAdapter) tendrías que declarar un objeto SQLiteOpenHelper y otro SQLiteDatabase por cada base de datos que quieras crear.

      En el constructor de DBAdapter se inicializarán todos los objetos OpenHelper que tengas, con sus respectivos nombres y versiones, y en el método open() habría que inicializar los correspondientes objetos SQLiteDatabase y las diferentes tablas si utilizas la orientación a objetos explicada en los siguientes enlaces:
      Programación Android, Ejemplo de Bases de datos & ListView I
      Programación Android, Ejemplo de Bases de datos & ListView II
      Programación Android, Ejemplo de Bases de datos & ListView III
      Programación Android, Ejemplo de Bases de datos & ListView IV

Deja un comentario