SQLite es el motor de base de datos integrado en Android dada sus características de potencia, escalabilidad y tamaño. Esta base de datos permite guardar bases de datos de forma muy sencilla dentro del dispositivo. Hay que tener en cuenta que el uso de este tipo de bases de datos tan solo se usará si no se quiere que los datos no sean compartidos entre dispositivos. Su uso se basa en un conjunto de objetos que permiten crear una estructura de la pase de datos, crear la propia base de datos y obtener una instancia de la misma. Para un uso efectivo los pasos serán los siguientes:

  1. Crear la escultura de la base de datos: este paso no es estrictamente necesario paro soluciona bastantes problemas. Aquí se define tanto el nombre de la tabla o tablas a crear como el nombre de los campos. En este punto se utilizará la interfaz BaseColumns.
  2. Crear la base de datos: mediante un objeto de tipo SQLiteOpenHelper se crea la base de datos particular utilizando el esquema del punto anterior.
  3. Obtener instancia de la base de datos: para su uso se creará una instancia de la base de datos creada en el punto anterior mediante un objeto de tipo SQLiteDataBase

Creación de la estructura

Dado por supuesto que se cuenta con un esquema de tablas con sus correspondientes campos, se creará una clase que represente el contenido de la tabla con el constructor y los métodos getter

public class Alumno {

    String nombre, apellido, direccion;
    int id, telefono;

    public Alumno( int id, String nombre, String apellido, String direccion, int telefono) {
        this.nombre = nombre;
        this.apellido = apellido;
        this.direccion = direccion;
        this.id = id;
        this.telefono = telefono;
    }

    public String getNombre() {
        return nombre;
    }

    public String getApellido() {
        return apellido;
    }

    public String getDireccion() {
        return direccion;
    }

    public int getId() {
        return id;
    }

    public int getTelefono() {
        return telefono;
    }
}

Además se creará una clase que contendrá a su vez otra clase estática y abstracta que implemente la interfaz BaseColumns donde se ubicarán variables estáticas con los nombres de las tablas y los campos que se utilizarán. El motivo de extender de BaseColumns es poder contar con un campo (que se utilizará como clave) necesario para algunas características de la base de datos.

public class EsquemaUsuario {

    public static abstract class EntradaUsuario implements BaseColumns{

        public static final String NOMBRE_TABLA = "usuarios";
        public static final String NOMBRE = "nombre";
        public static final String APELLIDO = "apellido";
        public static final String DIRECCION = "direccion";
        public static final String TELEFONO = "telefono";
        
    }
}

Esté campo extra que provee la interfaz BaseColumns es _id, por lo que no habrá que definirlo en esta clase.

Creación de la base de datos

Mediante una clase que extienda de SQLiteOpenHelper se maneja la creación de la base de datos y la posibilidad de manejar los datos que se tocarán en la aplicación. Tiene 2 métodos precargados que son el onCreate() y onUpgrade(). El primero será llamado cuando creemos la base de datos y ejecutará una query para crear la tabla. El segundo será llamado cuando la base de dato sea actualizada. Del mismo modo esta clase tendrá que tener un constructor para que puede ser creada desde otra clase, el cual tendrá los siguientes parámetros

  • context: Contexto de la aplicación donde se ejecutará la base de datos.
  • name: nombre del archivo que se creará. Es importante que este tenga extension .db. El fichero se creará en la ruta /data/data/nombre_paquete/database/archivo.db .
  • CursorFactory: objeto que manejará la creación u obtención del información. Inicialmente se utilizará null.
  • version: número que indicará cual ella versión de la base de datos. Este número se utilizará para ejecutar el método onUpgrade() en el caso de ser mayor que el actual o downUpgrade() en el caso de ser menor.

En el método onCreate se ejecutará la sentencia que cree la base de datos. Para ello se utilizará la estructura creada en el primer punto mediante el método execSQL()

public class UsuarioOpenHelper extends SQLiteOpenHelper {

    public static final int VERSION = 1;
    public static final String NOMBRE_DB = "Usuarios.db";

    public UsuarioOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("CREATE TABLE "+EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA+" ("
                +EsquemaUsuario.EntradaUsuario._ID+" INTEGER PRIMARY KEY AUTOINCREMENT,"
                +EsquemaUsuario.EntradaUsuario.NOMBRE+" TEXT NOT NULL,"
                +EsquemaUsuario.EntradaUsuario.APELLIDO+" TEXT NOT NULL,"
                +EsquemaUsuario.EntradaUsuario.DIRECCION+" TEXT NOT NULL,"
                +EsquemaUsuario.EntradaUsuario.TELEFONO+" INTEGER NOT NULL)");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
       sqLiteDataBase.exeqSQL("DROP TABLE IF EXISTS "+ EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA);
       onCreate(sqLiteDatabase);
    }
}

Instancia de la base de datos

En la clase donde se vaya a utilizar la base de datos se obtendrá una instancia de la misma a través del objeto SQLiteOpenHelper. Para ello además de crearlo mediante su constructor, se utilizan los métodos:

  • getRedeableDataBase: en el caso de querer consultar datos de la bd
  • getWritebleDataBase: en el caso de querer escribir datos de la bd
public class SqliteActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sqlite);

        UsuarioOpenHelper usuarioOpenHelper = new UsuarioOpenHelper(getApplicationContext(),UsuarioOpenHelper.NOMBRE_DB,null,UsuarioOpenHelper.VERSION);
        SQLiteDatabase dbUsuarios = usuarioOpenHelper.getReadableDatabase();
        SQLiteDatabase dbUsuariosEscritura = usuarioOpenHelper.getWritableDatabase();
    }
}

Una vez se obtiene la instancia de la base de datos ya puede ser manipulada.

Manejar datos

En una base de datos CRUD de SQLite existen multitud de formas de manejar los datos. En concreto se explicarán dos: ejecución directa de SQL y ejecución mediante la ejecución de métodos asociados. Para poder comprender mejor toda la sintaxis del lenguaje se puede visitar la página web oficial.

Antes de ejecutar cualquier método CRUD primero se obtendrá una instancia de lectora o escritura y una vez terminada la operación se cerrará la base de datos mediante el método close.

Mediante método insert()

Ejecuta el método insert al cual se le pasa un objeto de tipo ContentValue. El objeto ContentValue utiliza el método put con un par clave-valor, donde la clave es el nombre de la columna donde se quiere insertar. Por ultimo al método inserta se le pasa el nombre de la tabla, nombre de la columna que admite parámetros null y por último el objeto ContentValue

SQLiteDatabase dbUsuariosEscritura = usuarioOpenHelper.getWritableDatabase();
ContentValues nuevoRegistro = new ContentValues();
nuevoRegistro.put(EsquemaUsuario.EntradaUsuario.NOMBRE, "Nombre1");
nuevoRegistro.put(EsquemaUsuario.EntradaUsuario.APELLIDO, "Apellido1");
nuevoRegistro.put(EsquemaUsuario.EntradaUsuario.DIRECCION, "Direccion1");
nuevoRegistro.put(EsquemaUsuario.EntradaUsuario.TELEFONO, 111111);
dbUsuariosEscritura.insert(EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA,null,nuevoRegistro);
dbUsuariosEscritura.close();

Borrado de datos

El borrado de datos se realiza de la siguiente forma:

Mediante método delete()

Ejecuta el método remove al cual se le pasa directament la tabla de la que se quiere borrar, la cláusula where que se debe cumplir y por último los argumentos de la cláusula where en el caso de ser necesario

dbUsuariosEscritura.delete(EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA, EsquemaUsuario.EntradaUsuario.NOMBRE+"=?",new String[]{"Nombre1"});
dbUsueriosEscritura.close();

Actualizar datos

Mediante método update()

Ejecuta el método update al cual se le pasa la tabla sobre la que se actúa, un objeto ContentValue donde se guarda con un par clave – valor la el nuevo registro (la clave será la columna que se quiere actualizar), la cláusula where que se debe cumplir y los argumentos que recibe la cláusula where

ContentValues actualizaUsuario = new ContentValues();
actualizaUsuario.put(EsquemaUsuario.EntradaUsuario.NOMBRE,"NombreNuevo");
dbUsuariosEscritura.update(EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA,actualizarUsuario,EsquemaUsuario.EntradaUsuario.NOMBRE+"=?",new String[]{"Nombre1"});
dbUsuariosEscritura.close();

Consultar datos

Para consultar registros se utiliza es un objeto de tipo Cursor. Al igual que pasa en los casos anteriores se utiliza un objeto de tipo database creado con permisos de escritura. Este objeto cursor se rellana mediante dos formas:

rawQuery()

Método que recibe la sentencia query y el array de argumentos que recibe la cláusula.

ArrayList listaAlumnos = new ArrayList();
SQLiteDatabase dbUsuariosLectura = usuarioOpenHelper.getReadableDatabase();
Cursor c = dbUsuariosLectura.rawQuery("SELECT * FROM usuarios", null);

query()

La otra posibilidad para consultar datos es el métodéo query, al cual se le pasa los siguientes parámeátros:

  • table: Nombre de la tabla a consultar
  • columns: nombre de las columnas que se quieren consultar. Si se quieren ver todas se pasa un parametro nula
  • selection: clausula where en el caso de haberla
  • selectionArgs: array con los parámetros que se pasan en la cléusula where
  • String groupBy: groupBy: clausula GROUP BY.
  • String having: having: cláusula HAVING.
  • String orderBy: orderBy: cláusula ORDER BY.
Cursor c = dbUsuariosLectura.query(EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA,null,null,null,null,null,null);

Una vez el objeto cursos está relleno tan solo queda leerlo. Para ello hay que recorrerlo y obtener por registro con los métodos:

  • moveToFirts: para situar el cursos en la primera posicion
  • moveToNext: para pasar al siguiente registro
  • getTipo(int): para obtener el dato colocado en la posición determinada
  • getColumnIndex(string): para obtener el indice de la columna con el nombre determinado. Este indice es el que se le pasará al método anterior
c.moveToFirst();
do {
    int id = c.getInt(c.getColumnIndex(EsquemaUsuario.EntradaUsuario._ID));
    String n = c.getString(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.NOMBRE));
    String a = c.getString(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.APELLIDO));
    String d = c.getString(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.DIRECCION));
    int t = c.getInt(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.TELEFONO));
    Alumno alumno = new Alumno(id,n,a,d,t);
    listaAlumnos.add(alumno);
}
while (c.moveToNext());

De esta forma si se quiere rellenar un objeto listview  se podría hacer de la siguiente forma

Cursor c = dbUsuariosLectura.query(EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA,null,null,null,null,null,null);
c.moveToFirst();
while (c.moveToNext()){
    int id = c.getInt(c.getColumnIndex(EsquemaUsuario.EntradaUsuario._ID));
    String n = c.getString(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.NOMBRE));
    String a = c.getString(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.APELLIDO));
    String d = c.getString(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.DIRECCION));
    int t = c.getInt(c.getColumnIndex(EsquemaUsuario.EntradaUsuario.TELEFONO));
    Alumno alumno = new Alumno(id,n,a,d,t);
    listaAlumnos.add(alumno);
}
lista.setAdapter(new ArrayAdapter<CharSequence>(SqliteActivity.this,android.R.layout.simple_list_item_1,listaAlumnos));

Existe una manera más sencilla de crear un adaptador partiendo de un cursor con resultados de base de datos y recibe el nombre de SimpleCursorAdapter en cual recibe los siguientes parámetros:

  • context: contexto donde se encuentra la lista.
  • layout: layout que se usará para representar los ítem de cada fila.
  • cursor: cursor obtenido en la conexión con la bd
  • from: conjunto de nombres de columnas que se quieren represenar en el listview.
  • to: sitio donde se colocarán los datos del punto anterior
  • flags: identificador para el comportamiento del adaptador.
Cursor c = dbUsuariosLectura.query(EsquemaUsuario.EntradaUsuario.NOMBRE_TABLA,null,null,null,null,null,null);
SimpleCursorAdapter adaptador = new SimpleCursorAdapter(
        SqliteActivity.this
        android.R.layout.simple_list_item_1,
        c,
        new String[]{EsquemaUsuario.EntradaUsuario.NOMBRE},
        new int[]{android.R.id.text1},
        SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER
);
lista.setAdapter(adaptador);