You are on page 1of 18

Tutorial De Bases De Datos SQLite En Aplicaciones

Android
Continuando con nuestros tutoriales de desarrollo android, en esta ocasin
veremos cmo usar bases de datos en SQLite para no perder la informacin de nuestras
aplicaciones Android.
A medida que vayamos avanzando veremos la utilidad de clases como
SQLiteOpenHelper, SQLiteDatabase, Cursor, CursorAdapter y de Herramientas
como sqlite3 y SQLite Browser.
Con el fin de facilitar tu aprendizaje usaremos un ejemplo de gua, que te permitir ir la
prctica en paralelo a las teoras y conceptos estudiados. Puedes descargar los recursos
desde aqu:

Qu es SQLite?
Es un ligero motor de bases de datos de cdigo abierto, que se caracteriza por
mantener el almacenamiento de informacin persistente de forma sencilla. A diferencia
de otros SGBD como MySQL, SQL Server y Oracle DB, SQLite tiene las siguientes
ventajas:

No requiere el soporte de un servidor: SQLite no ejecuta un proceso para


administrar la informacin, si no que implementa un conjunto de libreras
encargadas de la gestin.
No necesita configuracin: Libera al programador de todo tipo de
configuraciones de puertos, tamaos, ubicaciones, etc.

Usa un archivo para el esquema: Crea un archivo para el esquema completo de


una base de datos, lo que permite ahorrarse preocupaciones de seguridad, ya que
los datos de las aplicaciones Android no pueden ser accedidos por contextos
externos.

Es de Cdigo Abierto: Esta disponible al dominio pblico de los


desarrolladores al igual que sus archivos de compilacin e instrucciones de
escalabilidad.

Es por eso que SQLite es una tecnologa cmoda para los dispositivos mviles. Su
simplicidad, rapidez y usabilididad permiten un desarrollo muy amigable.
SQLite tiene ciertas limitaciones en algunas operaciones. Por ejemplo, no se puede
implementar las clausulas FULL OUTER JOIN y RIGHT OUTER JOIN. Aunque en la
mayora de casos esto no afectar, siempre habrn otras alternativas como JavaDB o
MongoDB.
Para comenzar a probar nuestras bases de datos, quisiera explicarte un poco ms sobre
el ejemplo prctico que vamos a desarrollar. Se trata de una aplicacin llamada
Quotilius. Cuyo objetivo es guardar una lista de frases celebres.

Debemos almacenar el cuerpo de la frase y el autor que la trajo al mundo. El siguiente


sera un bosquejo rpido de como se vera la tabla de frases:
_id
1
2
3
4
5

body
author
El ignorante afirma, el sabio duda y
Aristteles
reflexiona
Hay derrotas que tienen ms
Jorge Luis
dignidad que la victoria
Borges
Si buscas resultados distintos, no
Albert Einstein
hagas siempre lo mismo
Donde mora la libertad, all est mi Benjamin
patria
Franklin
Ojo por ojo y todo el mundo acabar Mahatma
ciego
Gandhi

La idea es proporcionarle al usuario la posibilidad de aadir nuevas frases desde la


Action Bar.
En este artculo asumir que tienes conocimientos bsicos en SQLite y que ya tienes
claro como disear una base de datos.

Ejemplo De Aplicacin Android Con SQLite


Quotilius se compone de dos actividades para su funcionamiento. La primera es
Main.java. Esta actividad est basada en una lista, donde ubicaremos las frases del
usuario. No definiremos su archivo de diseo debido a que ser una subclase de
ListActivity. As que usaremos el layout del sistema
android.R.layout.list_content para inflar la actividad.

Nota: Si quieres un proyecto en Android Studio completo con ms de 1000 frases en


SQLite, te recomiendo descargar la plantilla The Quotes Garden. Es un buen ejemplo,
adems de que puedes usarlo para tus propios proyectos.
La segunda actividad se llama Form , la cual cumple la funcin de formulario para
ingresar el cuerpo de la frase y el autor mediante dos Edit texts. Se ejecutar cuando
presionamos el Action Button Aadir. Observemos su previsualizacin:

La comunicacin entre ambas actividades se realiza a travs de un Intent explicito. Este


nos permite obtener los datos que el usuario ingres en Form para poder usarlos en
Main e ingresarlos en la base de datos y al mismo tiempo actualizar nuestro ListView.
Lo primero que hars ser enviar un Intent para ejecutar la actividad Form a travs de
un canal de comunicacin:
//Cdigo de envo
public final static int ADD_REQUEST_CODE = 1;
...
//Iniciando la actividad Form
Intent intent = new Intent(this, Form.class);
//Inicio de la actividad esperando un resultado
startActivityForResult(intent, ADD_REQUEST_CODE);

Una vez el usuario este en la actividad y haya presionado el botn de Guardar,


devuelves los valores de texto los EditTexts por el mismo canal hacia Main:
//Obtener los datos de los campos
EditText quoteField = (EditText) findViewById(R.id.quoteField);
EditText authorField = (EditText) findViewById(R.id.authorField);

//Nuevo Intent con Extras


Intent backData = new Intent();
backData.putExtra("body", quoteField.getText().toString());
backData.putExtra("author", authorField.getText().toString());
//Enviar la informacin
setResult(RESULT_OK, backData);

Luego recibes los datos con el mtodo onActivityResult() y realizas las operaciones
necesarias para guardar los datos en la base de datos:
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ADD_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
//Insertar registro en la base de datos
}
}

Hasta aqu hicimos un bosquejo rpido de la comunicacin entre ambas actividades. Si


te perdiste y an no sabes cmo funcionan los Intents, entonces visita nuestro tutorial
sobre Intents en Android para esclarecer ms este proceso de transmisin.

Crear Una Base De Datos En SQLite


Android SDK nos provee una serie de clases para administrar nuestro archivo de base
de datos en SQLite.
Normalmente cuando conectamos otro gestor de bases de datos tenemos que validar los
datos del equipo, el usuario y el esquema, pero con SQLite no se requiere nada de eso,
ya que podemos trabajar directamente sobre la base de datos.
La clase que nos permitir comunicar nuestra aplicacin con la base de datos se llama
SQLiteOpenHelper. Se trata de una clase abstracta que nos provee los mecanismos
bsicos para la relacin entre la aplicacin Android y la informacin.
Solo tienes que derivar de ella una subclase que se ajuste a tus necesidades y tendrs un
puente funcional hacia el archivo de datos.
As que implementaremos una nueva clase que extienda de SQLiteOpenHelper y la
llamaremos QuotesReaderDbHelper.
Veamos:
public class QuotesReaderDbHelper extends SQLiteOpenHelper {
public QuotesReaderDbHelper(Context context){
super(context,
DATABASE_NAME,//String name

null,//factory
DATABASE_VERSION//int version
);
}
@Override
public void onCreate(SQLiteDatabase db) {
//Crear la base de datos
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
//Actualizar la base de datos
}
}

A continuacin la explicacin del cdigo:


Estructura del constructor de la clase SQLiteOpenHelper
Recibe el contexto con el cual se relacionar el helper. Luego invoca a super , donde se
enva el contexto y 3 parmetros adicionales:

name: String

que representa el nombre del archivo con extensin .db donde se


almacenar la base de datos, que a su vez corresponde al nombre de la base de
datos.
factory: Asignamos null, por ahora no es necesario comprender el
funcionamiento de este parmetro.
version: Entero que representa la versin de la base de datos. Su valor inicial
por defecto es 1. Si en algn momento la versin es mayor se llama al mtodo
onUpgrade() para actualizar la base de datos a la nueva versin. Si es menor, se
llama a downUpgrade() para volver a una versin previa.

onCreate()
Este mtodo es llamado automticamente cuando creamos una instancia de la clase
SQLiteOpenHelper. En su interior establecemos la creacin de las tablas y registros.
Recibe como parmetro una referencia de la clase SQLiteDataBase, la cual representa
el esquema completo de la base de datos.
Por defecto el archivo de la base de datos ser almacenado en la direccin
/data/data/<paquete>/databases/<nombre-de-la-bd>.db de nuestro dispositivo
mvil.
onUpgrade()
Es ejecutado si se identific que el usuario tiene una versin antigua de la base de datos.
En su interior estableceremos instrucciones para modificar el esquema de la base de
datos, como por ejemplo eliminar todo el esquema y recrearlo, agregar una nueva tabla,
aadir una nueva columna, etc. Recibe tres parmetros:

db: Es la instancia de SQLiteDataBase que representa la base de datos.


oldVersion: Se trata de un entero que indica la Version antigua de la base

de

datos.

newVersion: Entero

que se refiere a la Version Nueva de la base de datos.

Crear Un Script O ContractClass De La Base De Datos


La forma en que una base de datos est estructurada (cantidad de tablas, registros,
ndices, etc.) y el conjunto de convenciones para nombrar sus objetos se les llama
Esquema. Por lo general el esquema inicial se guarda en un Script que nos permita
recuperar las condiciones previas en cualquier momento.
Con SQLite no es diferente, por lo que debes crear un esquema predefinido para
implementarlo a la hora de crear tu base de datos. La documentacin de Android nos
recomienda crear una clase llamada Contract Class. Esta clase guarda como constantes
todas las caractersticas de la base de datos, adems del cdigo SQL necesario para la
creacin, insercin, actualizacin, etc.
El esquema de la aplicacin Quotilius est basado en un diseo simple, el cual se
compone de una tabla que llamars Quotes con tres atributos: _id, cuerpo (body) y
autor (author).
Ahora solo queda implementar ese esquema en una clase que llamaremos
QuotesDataSource:
public class QuotesDataSource {
//Metainformacin de la base de datos
public static final String QUOTES_TABLE_NAME = "Quotes";
public static final String STRING_TYPE = "text";
public static final String INT_TYPE = "integer";
//Campos de la tabla Quotes
public static class ColumnQuotes{
public static final String ID_QUOTES = BaseColumns._ID;
public static final String BODY_QUOTES = "body";
public static final String AUTHOR_QUOTES = "author";
}
//Script de Creacin de la tabla Quotes
public static final String CREATE_QUOTES_SCRIPT =
"create table "+QUOTES_TABLE_NAME+"(" +
ColumnQuotes.ID_QUOTES+" "+INT_TYPE+" primary key
autoincrement," +
ColumnQuotes.BODY_QUOTES+" "+STRING_TYPE+" not
null," +
ColumnQuotes.AUTHOR_QUOTES+" "+STRING_TYPE+" not
null)";
//Scripts de insercin por defecto
public static final String INSERT_QUOTES_SCRIPT =
"insert into "+QUOTES_TABLE_NAME+" values(" +
"null," +

"\"El ignorante afirma, el sabio duda y


reflexiona\"," +

"\"Aristteles\")," +
"(null," +
"\"Hay derrotas que tienen mas dignidad que la

victoria\"," +

"\"Jorge Luis Borges\")," +


"(null," +
"\"Si buscas resultados distintos, no hagas
siempre lo mismo\"," +
"\"Albert Einstein\")," +
"(null," +
"\"Donde mora la libertad, all est mi patria\","
+
"\"Benjamin Franklin\")," +
"(null," +
"\"Ojo por ojo y todo el mundo acabar ciego\"," +
"\"Mahatma Gandhi\")";
private QuotesReaderDbHelper openHelper;
private SQLiteDatabase database;
public QuotesDataSource(Context context) {
//Creando una instancia hacia la base de datos
openHelper = new QuotesReaderDbHelper(context);
database = openHelper.getWritableDatabase();
}
}

En el anterior cdigo podemos notar los siguientes detalles:

Creamos una constante para el nombre de la tabla llamada QUOTES_TABLE_NAME


y otras dos para el tipo de datos que usaremos ( STRING_TYPE e INT_TYPE).
Creamos la clase interna ColumnQuotes para guardar el nombre de las columnas
de la tabla Quotes. En el caso del campo ID_QUOTES usamos una constante
BaseColumns._ID de Android con el valor _id.

Creamos la constante INSERT_QUOTES_INSERT tipo String para guardar una


sentencia SQL para crear la tabla.

Creamos la constante INSERT_QUOTES_SCRIPT tipo String para insertar todos los


datos inciales de nuestra tabla.

Como ves, es una clase muy completa que nos proporcionar flexibilidad al realizar
operaciones sobre la base de datos. Estas declaraciones facilitan la adaptacin del
esquema si en algn momento cambian los datos de las tablas o columnas.
Adicional a todas estas definiciones tenemos dos variables privadas: openHelper y
database. Ambas las usaremos en el constructor para acceder a la base de datos con el
mtodo getWritableDatabase(), el cual retorna en una instancia de SQLiteDatabase
que nos permitir leer y modificar la informacin de la base de datos directamente.

Crear La Base De Datos

Una vez terminado nuestro Esquema, procedemos a implementar los mtodos


onCreate() y onUpgrade() de nuestra clase QuotesReaderDbHelper:
public class QuotesReaderDbHelper extends SQLiteOpenHelper {
public static final String DATABASE_NAME = "Quotes.db";
public static final int DATABASE_VERSION = 1;
public QuotesReaderDbHelper(Context context){
super(context,DATABASE_NAME,null,DATABASE_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
//Crear la tabla Quotes
db.execSQL(QuotesDataSource.CREATE_QUOTES_SCRIPT);
//Insertar registros iniciales
db.execSQL(QuotesDataSource.INSERT_QUOTES_SCRIPT);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int
newVersion) {
//Aade los cambios que se realizarn en el esquema
}
}

Lo primero que hicimos fue crear atributos de clase para el nombre de la base de datos y
la versin. Para crear la tabla Quotes llamamos al mtodo execSQL() de
SQLiteDataBase.
Este mtodo ejecuta una sola sentencia SQL que no retorne en filas. Por lo que el
comando SELECT no es posible usarlo dentro de l.
Evita ejecutar mltiples sentencias en una sola invocacin del mtodo execSQL().
Puede que se ejecute la primera, pero las otras no surtirn efecto.
Ahora solo queda por instancear un objeto QuotesDataSource en Main para que se cree
nuestra base de datos:
//Crear nuevo objeto QuotesDataSource
dataSource = new QuotesDataSource(this);

Al ejecutar la aplicacin se supone que la base de datos habr sido creada con xito en
el sistema de archivos de Android. Pero Cmo comprobar que as fue?la respuesta
la encontramos en el uso de las siguientes herramientas.

La Herramienta sqlite3
sqlite3 es una herramienta de administracin para nuestras bases de datos SQLite a
travs de la lnea de comandos. Normalmente puedes descargarla de la pgina oficial de
SQLite, pero tanto como la distribucin de Android y Android Studio ya la traen
consigo.

Antes de ejecutarla en el dispositivo, primero usaremos la herramienta DDMS (Dalvik


Debug Monitor Server) de Android SDK, la cual permite visualizar las caractersticas
del dispositivo que se est ejecutando. En ella podemos visualizar estadsticas de
rendimiento, monitorear recursos y navegar por el sistema de archivos.
Si deseas ejecutarla solo presiona el siguiente icono en Android Studio:

Ahora dirgete a la pestaa File Explorer

Como ves, se visualizan todos los directorios que se encuentran en el dispositivo. As


que para ver si existe nuestro archivo de base de datos, iremos a la ruta de la cual
hablamos al inicio /data/data/<paquete>/databases/Quotes.db

Si todo sali bien, veremos nuestro archivo Quotes.db. Procede a gurdalo con el botn
de la parte superior derecha denominado Pull a file from the device. En la siguiente
seccin veremos algo interesante con l.

Ya que hemos comprobado que existe nuestra base de datos, iniciaremos sqlite3 dentro
del dispositivo. Sigue los siguientes pasos:
Paso #1
Inicia el terminal de Windows (cmd) o usa la pestaa Terminal de Android Studio:

Paso #2

Navega hasta el directorio platform-tools del SDK de Android. En mi caso la direccin


es: C:/Users/James/AppDataLocal/Android/android-studio/sdk/platform-tools. Recuerda
que para navegar a travs de carpetas en DOS se utiliza el comando cd.
Paso #3
Una vez hayas encontrado el directorio, digita la siguiente linea de comandos:
adb shell

Este comando conecta remotamente la consola de comandos del dispositivo Android


con tu consola local. Cuando ya ests conectado a la consola del AVD, vers en el
terminal algo como esto:
root@android:/ #

Paso #4
Inicia sqlite3 en el dispositivo con el siguiente comando:
root@android:/ # sqlite3 data/data/TUPAQUETE/databases/Quotes.db

La anterior instruccin accede a sqlite3 y al mismo tiempo le pide que abra la base de
datos expuesta en el directorio especificado. Si accedi a la base de datos vers los
siguientes mensajes:
SQLite version 3.7.11 2012-03-20 11:35:50
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite>

Paso #5
Usa el comando .schema de sqlite3 para ver el resumen del esquema de la base de datos
Quotes:
CREATE TABLE Quotes(_id integer primary key autoincrement,body text
not null,author text not null);
CREATE TABLE android_metadata (locale TEXT);

El Esquema muestra que nuestra tabla Quotes ha sido creada correctamente. La tabla
llamada android_metadata es parte de la metainformacin de la base de datos, por lo
que siempre la encontrars.
Otra forma de comprobar el esquema de nuestra base de datos es usar sqlite3.exe en
nuestro equipo local.
Ve a la ruta para encontrar la carpeta platform-tools del SDK de Android y ejecuta la
aplicacin.
Luego usa .open para abrir el archivo en una ruta especificada o copia y pega el archivo
Quotes.db en la carpeta:

sqlite>.open Quotes.db

Luego usa .schema y averigua su contenido.

SQLite Browser
Si deseas conocer una herramienta ms visual, entonces SQLite Browser es una opcin
que te gustara considerar. Se trata de un editor para archivos de bases de datos SQLite
de cdigo abierto y sper sencillo de usar.
Solo basta con iniciarlo en tu pc y arrastrar el archivo Quotes.db a su editor.
Inmediatamente nos mostrar el esquema en forma de tablas con interfaz grfica de
usuario, adems de permitirnos editar la estructura y ejecutar sentencias SQL dentro de
ella.

Implementar CRUD En SQLite


A continuacin aprenders a Leer, Insertar, Modificar y Eliminar registros. Recuerda
que quin realiza este tipo de operaciones es la clase SQLiteDataBase.

Insertar Registros en SQLite


El mtodo cuya funcionalidad es aadir filas a nuestras tablas se llama insert().
Veamos un ejemplo:
//Nuestro contenedor de valores
ContentValues values = new ContentValues();
//Seteando body y author
values.put(QuotesDataSource.ColumnQuotes.BODY_QUOTES,"Nueva Frase");
values.put(QuotesDataSource.ColumnQuotes.AUTHOR_QUOTES,"Nuevo Autor");
//Insertando en la base de datos
database.insert(QUOTES_TABLE_NAME,null,values);

Lo primero que tenemos que hacer es crear un objeto del tipo ContentValues, el cual
permite almacenar una serie de datos(Valores) relacionados a una llave(Nombre de la
columna). Donde cada elemento es aadido con el mtodo put().
Luego invocamos a insert() a travs de la instancia de la base de datos. El primer
parmetro que recibe es el nombre de la tabla. El segundo parmetro establece que si el
objeto que contiene los valores est vaco, entonces no se debe insertar el registro en la
base de datos. Y el tercer parmetro es nuestro objeto ContentValues.
Con esta informacin ya puedes crear un mtodo de guardado en la clase
QuotesDataSource para aislar la complejidad de la actividad Main. A dicho mtodo le
llamars saveQuoteRow() y recibir el cuerpo de la frase y su autor:
public void saveQuoteRow(String body,String author){
//Nuestro contenedor de valores
ContentValues values = new ContentValues();
//Seteando body y author
values.put(QuotesDataSource.ColumnQuotes.BODY_QUOTES,body);
values.put(QuotesDataSource.ColumnQuotes.AUTHOR_QUOTES,author);
//Insertando en la base de datos
database.insert(QUOTES_TABLE_NAME,null,values);
}

Podras usar el comando execSQL() para ejecutar una sentencia INSERT, pero como
ests recibiendo datos externos, es mejor usar insert() para evitar inyecciones SQL.

Consultar Registros en SQLite


Para obtener los registros de nuestra tabla usaremos el mtodo query().
query (String table,
String[] columns,
String selection,
String[] selectionArgs,
String groupBy,
String having,
String orderBy)

Por ejemplo, si quisiramos consultar todos los datos de la tabla Quotes usaramos el
siguiente cdigo:
Cursor c = db.query(
"Quotes", //Nombre de la tabla
null, //Lista de Columnas a consultar
null, //Columnas para la clausula WHERE
null, //Valores a comparar con las columnas del WHERE
null, //Agrupar con GROUP BY
null, //Condicin HAVING para GROUP BY
null //Clausula ORDER BY
);

Este mtodo te ayuda a aadir todas las partes posibles de las cuales se podra componer
una consulta, adems que te protege de inyecciones SQL, separando las clausulas de los
argumentos. Ahora veamos el propsito de los parmetros:

table: Nombre de la tabla a consultar


columns: Lista de nombres de las columnas
obtener todas las columnas usas null.

selection: Es

selectionArgs[]: Es

groupBy: Aqu puedes

que se van a consultar. Si deseas

el cuerpo de la sentencia WHERE con las columnas a condicionar.


Es posible usar el placeholder ? para generalizar la condicin.
una lista de los valores que se usaran para reemplazar las
incgnitas de selection en el WHERE.
establecer cmo se vera la clausula GROUP BY, si es que

la necesitas.

having: Establece

la sentencia HAVING para condicionar a groupBy.

orderBy: Reordena

las filas de la consulta a travs de ORDER BY.

Debido a la simplicidad de nuestra consulta anterior, la mayora de parmetros fueron


null, ya que se consultan todas las columnas de la tabla y todos los registros. Pero si
quisieras consultar solo el cuerpo de aquellos registros donde el autor sea John D.
Rockefeller tendras que usar la siguiente clausula WHERE:
String columns[] = new String[]{ColumnQuotes.BODY_QUOTES};
String selection = ColumnQuotes.AUTHOR_QUOTES + " = ? ";//WHERE author
= ?
String selectionArgs[] = new String[]{"John D. Rockefeller"};
Cursor c = db.query(
"Quotes",
columns,
selection,
selectionArgs,
null,
null,
null
);

Se usa el parmetro selection para asignarle el nombre de la columna del cuerpo de la


frase y luego en el parmetro selectionArgs relacionas el valor a comparar.
Aprender ms sobre la clausula WHERE
Ahora, existe otro mtodo alternativo para realizar consultas llamado rawQuery(). Con
l debes crear un String que contenga todo el cdigo SQL de la consulta y lo pasamos
como parmetro.
Veamos:
database.rawQuery("select * from " + QUOTES_TABLE_NAME, null);

Si deseas crear una consulta generalizada usa el placeholder ? en la clausula WHERE.


Luego asignamos los valores a cada incgnita en el segundo parmetro:
String query = "select * from " + QUOTES_TABLE_NAME + "WHERE _id=?";
database.rawQuery(query, new String[]{"3"});

Tanto query() como rawQuery() retornan un objeto de tipo Cursor. Este objeto es un
apuntador al conjunto de valores obtenidos de la consulta. Al inicio el cursor apunta a
una direccin previa a la primera fila. La idea es leer cada fila moviendo el cursor a la
fila siguiente y as sucesivamente.
Emplea el mtodo booleano moveToNext() para recorrer el cursor. Su cometido es
apuntar al siguiente elemento del cursor, el cual retorna en true si fue posible o false si
ya no existen ms elementos.
Este concepto es similar a cuando vimos cursores en SQL Server o en MySQL. Donde
recorramos cada elemento con un bucle while hasta que ya no existieran ms elementos
que referenciar.
Veamos:
while(c.moveToNext()){
String body = c.getString(ColomunQuotes.BODY_QUOTES);
//Acciones con el valor obtenido
}

Como ves, usamos mtodos get para obtener el valor de cada columna a travs del
nombre o clave. Por ejemplo, al obtener el cuerpo de la frase usamos getString()
debido a que su tipo en la tabla es text. Si fueses a obtener el cdigo, entonces usas
getInt().
Puedes aprovechar este nuevo concepto e implementar un nuevo mtodo en la clase
QuotesDataSource llamado getAllQuotes(). Su objetivo es retornar en un cursor
todas las filas de la tabla Quotes, lo que asla la complejidad de la operacin sobre la
base de datos de la actividad Main:
public Cursor getAllQuotes(){
//Seleccionamos todas las filas de la tabla Quotes
return database.rawQuery(
"select * from " + QUOTES_TABLE_NAME, null);
}

Al igual que saveQuoteRow() y getAllQuotes(), puedes crear otros mtodos para


borrar, modificar o realiza consultas especificas. Tu objetivo siempre debe ser eliminar
dependencias entre la actividad y el manejo de la base de datos.

Borrar Registros en SQLite


Eliminar registros es muy sencillo, solo tenemos que usar el mtodo delete(). Recibe
como parmetros el nombre de la tabla, el estilo de la seleccin de la clausula WHERE y
los valores de comparacin para determinar que filas borrar.

Por ejemplo, eliminar la frase que tenga el cdigo 3:


String selection = ColumnQuotes.BODY_QUOTES + " = ?";
String[] selectionArgs = { "3" };
db.delete("Quotes", selection, selectionArgs);

Actualizar Registros en SQLite


En este caso usaremos el mtodo update(). Es exactamente el mismo estilo de uso que
los anteriores mtodos. Especificaremos el nombre de la tabla, los valores nuevos que
vamos a usar y luego pondremos las cadenas de la instruccin where y sus argumentos
comparativos:
//Nuestro contenedor de valores
ContentValues values = new ContentValues();
//Seteando body y author
values.put(QuotesDataSource.ColumnQuotes.BODY_QUOTES,"Nueva Frase");
values.put(QuotesDataSource.ColumnQuotes.AUTHOR_QUOTES,"Nuevo Autor");
//Clausula WHERE
String selection = ColumnQuotes.BODY_QUOTES + " = ?";
String[] selectionArgs = { "3" };
//Actualizando
database.update(QUOTES_TABLE_NAME, values, selection, selectionArgs);

La Clase CursorAdapter
Existe un adaptador especial para el manejo de bases de datos llamado CursorAdapter.
Esta clase permite poblar una lista a travs de un cursor. Es decir, el origen de datos no
ser una lista ni un arreglo, si no un cursor.
es una clase abstracta de la cual se ha de crear tu adaptador
personalizado. Con ArrayAdapter tenamos que sobrescribir el mtodo getView()
para inflar nuestras filas con los datos de la lista. Pero no es el caso con
CursorAdapter. Esta vez debemos sobrescribir dos mtodos aislados llamados
bindView() y newView().
CursorAdapter

es el encargado de poblar la lista con los datos del cursor y newView() es


quien infla cada view de la lista. Al implementar ambos mtodos no debemos
preocuparnos por iterar el curso, esto es manejado internamente.
bindView()

As que escribamos nuestra nueva clase QuotesAdapter. En bindView() simplemente


debemos obtener los valores de las columnas y setearlos en los text views del layout. Y
en newView() accedemos a la instancia del LayoutInflater a travs del parent y luego
invocamos inflate() para inflar nuestra fila.
Observemos:
public class QuotesAdapter extends CursorAdapter {

public QuotesAdapter (Context context, Cursor cursor) {


super(context, cursor);
}
public void bindView(View view, Context context, Cursor cursor) {
TextView body = (TextView)view.findViewById(R.id.bodyText);
//Setear el texto del a columna en la posicin 0 del cursor
body.setText(cursor.getString(cursor.getColumnIndex(0)));
TextView author = (TextView)view.findViewById(R.id.authorText);
author.setText(cursor.getString(cursor.getColumnIndex(1)));
}
public View newView(Context context, Cursor cursor, ViewGroup
parent) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
View view = inflater.inflate(R.layout.list_item, null, false);
return view;
}
}

Ahora solo debemos cargar nuestra actividad principal e instancear nuestro adaptador
con un cursor que apunte a todos los registros de nuestra tabla Quotes.
adapter = new QuotesAdapter(this, sourceData.getAllQuotes());
setAdapter(adapter);

Por razones de compatibilidad en los procesos de manipulacin de datos


CursorAdapter exige que uses en todas tus tablas una llave fornea cuya etiqueta sea
_id, si no lo haces se generar un error en tiempo de ejecucin.

La Clase SimpleCursorAdapter
Si el diseo de las filas de tu lista es sencillo, entonces la clase SimpleCursorAdapter
podra ahorrarte tiempo de desarrollo. Esta clase es una extensin de CursorAdapter
que posee una implementacin completa para los desarrolladores. Con ella no tenemos
que sobrescribir mtodos ni tampoco crear un archivo de diseo, ya que permite usar
layouts del sistema.
Nuestra aplicacin Quotilius tiene elementos sencillos, por qu slo usamos dos text
views para mostrar el cuerpo de la frase y el autor. Por esta razn podemos usar el
layout del sistema two_line_list_item. Fjate como sera la creacin de un nuevo
adaptador:
//Iniciando el nuevo Adaptador
adapter = new SimpleCursorAdapter(
this,//Context context
android.R.layout.two_line_list_item,//int layout
dataSource.getAllQuotes(),//Cursor c
new String[]
{ColumnQuotes.BODY_QUOTES,ColumnQuotes.AUTHOR_QUOTES},//String[] from
new int[]{android.R.id.text1, android.R.id.text2},//int[] to
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER//int flags
);
setListAdapter(adapter);

Comprendamos un poco los parmetros:


context: Es

el contexto donde se encuentra la lista, en este caso es la misma

actividad.
layout: Es el layour que usaremos para inflar los elementos de cada fila. En
nuestro caso usamos el prefabricado por Android para los elementos con dos text
views

c: Es

el cursor que representa el origen de datos para el adaptador. Asignamos el


cursor hacia todos los registros de la tabla Quotes.

from: Es

to: Es

flags: Es un bandera para establecer el comportamiento del adaptador.


FLAG_REGISTER_CONTENT_OBSERVER registra un observador adherido al cursor

un arreglo de Strings que contiene el nombre de las columnas a


consultar. Usamos los nombres de las columnas que contiene ColumnQuotes.
un arreglo de enteros con las referencias directas de los text views en el
layout. Deben tener el mismo orden que las columnas. Los TextViews dentro de
two_line_list_item.xml se llaman text1 y text2 respectivamente.

para saber cundo cambio su informacin y as refrescar la lista.


Finalmente completaremos el mtodo onActivityResult() para guardar el nuevo
registro. Si la actividad Form retorna los datos de forma correcta, entonces lo primero
que debemos realizar es obtener los extras que trae el Intent de regreso, luego
insertamos el nuevo registro con el mtodo saveQuoteRow() y por ltimo usamos el
mtodo changeCursor() para actualizar el cursor y as refrescar los elementos de la
lista:
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ADD_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
//Insertando el registro con los datos del formulario
String body = data.getStringExtra("body");
String author = data.getStringExtra("author");
dataSource.saveQuoteRow(body,author);
//Refrescando la lista
adapter.changeCursor(dataSource.getAllQuotes());
}
}
}