SESIÓN 5 MANEJO DE BASES DE DATOS SQLITE



Documentos relacionados
ALMACENAMIENTOS DE DATOS EN ANDROID CON SQLITE

Ejercicios - Persistencia en Android: ficheros y SQLite

Android Creación de una aplicación sencilla: Forwarding - Página 1 -

Ejercicios - Persistencia en Android: proveedores de contenidos y SharedPreferences

MODELO DE IMPLEMENTACIÓN

1.- Creamos un proyecto al que llamaremos MusicaMovil.

Persistencia. Mecanismos de persistencia. Preferencias. Curso 12/13

Curso 12/13. Desarrollo de Aplicaciones Android. Persistencia

PRACTICAS DE ANDROID 12 - Lanzar un segundo "Activity" y pasar parámetros Problema:

PHPMYADMIN Y MYSQL. Para gestionar la base de datos MySQL, lo haremos desde la aplicación PhpMyAdmin.

Crear una Activity en Android. Paso por paso

Práctica sobre compartición de instancias remotas.

TP Nº4 Android - SQLite Fecha Miércoles 2014/08/29 Profesor: Pablo Ulman (Polshu)

La funcionalidad básica es la del proyecto 1 (Pacman III). Sobre ella reemplazamos la interfaz de usuario para adaptarla al nuevo entorno

Ejercicio 4. Manejo de Layouts en Android. Android Con Java. Ejercicio 4. Manejo de Layouts en Android. Curso de Android con Java

GESTIÓN DOCUMENTAL PARA EL SISTEMA DE CALIDAD

MANUAL DE AYUDA HERRAMIENTA DE APROVISIONAMIENTO

Manual del Protocolo XML-RPC de Mensajería Negocios

CODIGO PROYECTO: AppPixelproServicioWeb Proyecto Android - Servicio Web

En cualquier caso, tampoco es demasiado importante el significado de la "B", si es que lo tiene, lo interesante realmente es el algoritmo.

Las propiedades de la clase en java es el equivalente a las variables globales en lenguajes estructurados como el C.

Almacenamiento de datos. JOSE LUIS BERENGUEL GÓMEZ Febrero 2012

Manual CMS Mobincube

1. El entorno de desarrollo Eclipse

Objetivos de la práctica: - Practicar uso de ficheros: abrir, cerrar y tratamiento de información contenida en el fichero.

Adaptación al NPGC. Introducción. NPGC.doc. Qué cambios hay en el NPGC? Telf.: Fax.:

Curso PUDE. Desarrollo de Aplicaciones Móviles en Android

Persistencia en Android: ficheros y SQLite

Programación Orientada a Objetos. Java: Excepciones

Dossier de prácticas

V Manual de Portafirmas V.2.3.1

Administración de la producción. Sesión 10: Gestor de Base de Datos (Access)

%& %)& '$!%*+ $, %%%&$ %%

MANUAL DE AYUDA MÓDULO PDA ALMACEN E INVENTARIO

Modulo 1 El lenguaje Java

1. Ejemplo de clase : La clase Cuenta 2. Uso de la clase Cuenta. 3. Métodos y objetos receptores de mensajes (Importante)

Desarrollo de Servicios Web con JBuilder

Programación Android. Alejandro Alcalde. elbauldelprogramador.com

Introducción al lenguaje Java

Curso de Java POO: Programación orientada a objetos

GUIA APLICACIÓN DE SOLICITUDES POR INTERNET. Gestión de Cursos, Certificados de Aptitud Profesional y Tarjetas de Cualificación de Conductores ÍNDICE

Trabajos de Ampliación. Bases de datos NoSQL.

Practica 11: Conexión de Java con Bases de datos Access

CONSULTAS DE RESUMEN SQL SERVER Manual de Referencia para usuarios. Salomón Ccance CCANCE WEBSITE

TUTORIAL DESARROLLO DE APLICACIONES PARA EVOLUTION CON MS ACCESS

Gestión de Retales WhitePaper Noviembre de 2009

CASO PRÁCTICO. ANÁLISIS DE DATOS EN TABLAS DINÁMICAS

Programa diseñado y creado por Art-Tronic Promotora Audiovisual, S.L.

A- CREAR COPIA FÍSICA Y HEREDAR REGISTRO DE CONFIGURACIÓN

Manual de rol gestor de GAV para moodle 2.5

Tema 2: Diseño de servicios para móviles

BASES DE DATOS - Microsoft ACCESS 2007-

Programación orientada a objetos

MANUAL PARA EMPRESAS PRÁCTICAS CURRICULARES

Proceso de cifrado. La fortaleza de los algoritmos es que son públicos, es decir, se conocen todas las transformaciones que se aplican al documento

MANUAL DE LA APLICACIÓN HELP DESK

Combinar comentarios y cambios de varios documentos en un documento

Cómo creo las bandejas del Registro de Entrada /Salida y de Gestión de Expedientes?

Programación Orientada a Objetos con Java

Programación Orientada a Objetos. Java: Excepciones

COMANDOS DE SQL, OPERADORES, CLAUSULAS Y CONSULTAS SIMPLES DE SELECCIÓN

Introducción a la programación orientada a objetos

Manual de NetBeans y XAMPP

2.4. BASES DE DATOS SQLITE

Notas para la instalación de un lector de tarjetas inteligentes.

ESCUELA SUPERIOR DE INFORMATICA Prácticas de Estadística UNA SESIÓN EN SPSS

Microsoft Access. Microsoft Access es una herramienta de Microsoft para la definición y manipulación de bases de datos.

EXAMEN FINAL Metodología y Programación Orientada a Objetos. Curso Cuatrimestre de otoño. 17 de Enero de 2011

Apuntes de ACCESS. Apuntes de Access. Campos de Búsqueda:

MANUAL DE AYUDA. SAT Móvil (Movilidad del Servicio Técnico)

Trazabilidad ERP Microsa Gestión de Lotes

Herramienta Encuestas. MiAulario

Traslado de Copias y Presentación de Escritos. Manual de Usuario V.3.1

Introducción al manejo de Bases de Datos con SQLite. Version Android

MANUAL DE LA APLICACIÓN DE ENVÍO DE SMS

Examen Junio- Grupo A Lunes 17 de Junio - Programación en C++ Pág. 1

Segunda práctica de Programación 2

Curso PUDE. Desarrollo de Aplicaciones Móviles en Android

1. DML. Las subconsultas

Formularios. Formularios Diapositiva 1

Solución al Examen de Prácticas de Programación (Ingeniería Informática)

Aplicación Android de Asistencia al Caminante

SIGUIENDO EL CAMINO Prerrequisitos: Tener adecuadamente configurado los ajustes de voz/sonidos en configuración Avisos Voz/sonidos

GedicoPDA: software de preventa

Manual de uso de Moodle para alumnos

Interfaz de usuario Layout Vistas Adaptadores Eventos de interacción Estilos y temas

13.1. Tablas dinámicas de Excel

NORMA 34.14(SEPA) 05/11/2013

Operación de Microsoft Word

Consultas con combinaciones

Java Inicial (20 horas)

STRATO LivePages Inicio rápido

Utilidades para el control de stock de los artículos

ESTÁNDAR DESEMPEÑO BÁSICO Recopila información, la organiza y la procesa de forma adecuada, utilizando herramientas tecnológicas.

A continuación se describen cuáles son los elementos principales de las tablas, cómo crear una y cómo modificarla.

GVisualPDA Módulo de Almacén

Uso del Programa Gantt Project

RESUMEN DE CONCEPTOS BASICOS DE PROGRAMACION JAVA

Manual de Usuario - Traslado de Copias Versión Procurador

Transcripción:

SESIÓN 5 MANEJO DE BASES DE DATOS SQLITE Contenidos Resumen...1 Práctica guiada 7: ListaCompra...1 Implementación de la base de datos...2 Actividad principal: ListaCompraActivity...6 Actividad secundaria: NuevoProductoActivity...9 Resumen En esta quinta sesión del curso de iniciación a Android se aprenderán los conceptos básicos para crear aplicaciones que trabajen con una base de datos SQLite. Se diseñará una base de datos con una única tabla y los métodos de consulta, modificación y eliminación correspondientes. Además se avanzarán en cuestiones como el diseño y la personalización de interfaces que utilicen un componente ListView. También, por primera vez iniciaremos una actividad con startactivityforresult esperando que la actividad llamada devuelva un resultado una vez haya finalizado, y gestionando ese resultado en el método onactivityresult. Práctica guiada 7: ListaCompra La aplicación que vamos a crear permite añadir una serie de productos a una lista de la compra. La lista de elementos se almacenará en una base de datos SQLite. Para cada elemento de la lista se guardará el nombre del producto y la cantidad. La aplicación permitirá añadir elementos a la lista y mostrar los elementos que ya existen en la misma. En la siguiente práctica guiada se ampliará la aplicación para que se puedan modificar o eliminar los productos de la lista a través de un menú contextual y además se incluirá un menú de la aplicación. Para comprender un poco mejor los pasos a realizar, describiremos como es el diseño de la aplicación. Constará de los siguientes componentes: 1. Actividad principal: ListaCompraActivity. 2. Actividad secundaria: NuevoProductoActivity. 3. Gestión de la base de datos: ListaCompraDatabaseAdapter. Crea un nuevo proyecto Android con los siguientes datos: Nombre del proyecto: ListaCompra. SDK: 2.1 (API Level 7). Nombre de la aplicación: ListaCompra. -1-

Nombre del paquete: com.cursoandroid. Nombre de la actividad: ListaCompraActivity. Implementación de la base de datos Creamos un nuevo fichero.java que contendrá la clase ListaCompraDatabaseAdapter pulsando con el botón derecho del ratón en el elemento del paquete del proyecto Eclipse: src/cursoandroid, y seleccionando la opción del menú contextual new>class. Esta clase contendrá los métodos necesarios para crear la base de datos e insertar, actualizar y eliminar elementos de la misma. La base de datos contendrá una única tabla con tres columnas: id: identificador de la fila de este elemento. producto: nombre del producto a comprar. cantidad: número de productos que se necesitan comprar. Para facilitar la labor de uso de la base de datos, utilizaremos un objeto de tipo SQLiteOpenHelper. Implementaremos este objeto a través de una clase interna privada dentro del propio fichero (también podría hacerse en un fichero a parte) que llamaremos DatabaseHelper. Este objeto únicamente contendrá el constructor de la clase y los métodos oncreate y onupgrade que se ejecutarán cuando la base de datos se cree por primera vez (cuando no existe aún en el dispositivo), y cuando haya habido una actualización de la base de datos, respectivamente. Este sería el código de esta clase interna: private class DatabaseHelper extends SQLiteOpenHelper{ public DatabaseHelper(Context context) { super(context, DATABASE_NOMBRE, null, DATABASE_VERSION); public void oncreate(sqlitedatabase db) { db.execsql(crear_database); public void onupgrade(sqlitedatabase db, int oldversion, int newversion) { Log.w(TAG, "Actualizando base de datos de la versión " + oldversion + " a la versión " + newversion + ". Se perderán todos los datos."); db.execsql("drop TABLE IF EXISTS productos"); oncreate(db); //end_databasehelper El código de las constantes DATABASE_NOMBRE, DATABASE_VERSION y CREAR_DATABASE está declarado previamente aunque se muestran más adelante en este documento. El constructor DatabaseHelper(Context context) recibe el contexto de la aplicación al que pertenece la base de datos. La inicialización que se hace en este constructor se produce con la llamada al constructor de la clase padre (super) que recibe: el contexto de la aplicación, el nombre de la base de datos, un objeto SQLiteDatabase.CursorFactory que en nuestro caso no será necesario (null) y la versión de la base de datos. El método oncreate(sqlitedatabase db) recibe el objeto que contendrá la base de datos. A este objeto, mediante la llamada al método execsql, le informamos de las sentencias SQL para crear las tablas de la base de datos. -2-

El método onupgrade(sqlitedatabase db, int oldversion, int newversion) debe contener las sentencias necesarias para el mantenimiento de la base de datos en caso de alguna actualización, por ejemplo si se modifica una tabla, se añade una tabla nueva, se eliminan tablas, etc. Tal y como hemos implementado este método, si hubiera alguna actualización se perderían todos los datos almacenados en la lista de la compra. Como hemos dicho al inicio de esta sección, el objeto DatabaseHelper se utiliza para facilitar la labor de manipulación de la base de datos. Por tanto, la clase ListaCompraDatabaseAdapter contendrá un objeto de este tipo, a través del cual haremos las llamadas correspondientes para insertar/modificar/eliminar elementos. Veamos cuáles son las constantes y atributos definidos para esta clase: // Definición de la base de datos y las tablas private static final String DATABASE_NOMBRE = "dbcompra"; private static final String DATABASE_TABLA = "productos"; private static final int DATABASE_VERSION = 1; private static final String TAG = "ListaCompraDatabaseAdapter"; // Constantes para definir los nombres de las columnas de la tabla productos public static final String CLAVE_PRODUCTO = "producto"; public static final String CLAVE_CANTIDAD = "cantidad"; public static final String CLAVE_ID = "_id"; // Columnas para la proyección de las consultas private static final String[] COLUMNAS_CONSULTA = {CLAVE_ID, CLAVE_PRODUCTO, CLAVE_CANTIDAD; // Sentencia SQL para la creación de la base de datos private static final String CREAR_DATABASE = "create table " + DATABASE_TABLA + " ( + CLAVE_ID + integer primary key autoincrement, " + CLAVE_PRODUCTO + " text not null, " + CLAVE_CANTIDAD + " integer not null);"; // ATRIBUTOS PRIVADOS private DatabaseHelper dbhelper; private SQLiteDatabase db_compra; private final Context db_context; La declaración de las constantes es autodescriptiva. Destacaremos la sentencia SQL de creación de la base de datos, donde se crea una única tabla productos y se establece la columna id como clave primaria y las columnas producto y cantidad que no pueden estar vacías. Pasamos a describir los atributos privados usados: DatabaseHelper dbhelper. Objeto del tipo de la clase interna privada (ver código anterior). SQLiteDatabase db_compra. A través de este objeto ejecutaremos las sentencias SQL de consulta/modificación de las tablas de la base de datos. Context db_context. Contexto de la aplicación. Necesitamos guardar la referencia al contexto ya que es usado internamente cuando se realiza la apertura de la base de datos. Para que una actividad de nuestra aplicación ListaCompra pueda utilizar la base de datos, deberá construir un objeto de tipo ListaCompraDatabaseActivity e indicar que se desea abrir la base de datos. El motivo de independizar la construcción del objeto de la apertura de la base de datos es optimizar los recursos, únicamente se abre la base de datos cuando se requiere alguna consulta sobre la misma, una vez finalizada la tarea, se cerrará la conexión para liberar dichos recursos. A continuación se muestra el código que gestiona dichas acciones: la construcción del objeto y la apertura y cierre de la base de datos. -3-

public ListaCompraDatabaseAdapter(Context ctx) { this.db_context = ctx; public ListaCompraDatabaseAdapter open() throws SQLException { this.dbhelper = new DatabaseHelper(this.db_context); this.db_compra = this.dbhelper.getwritabledatabase(); return this; public void close() { this.dbhelper.close(); La única acción que realiza el constructor es almacenar el contexto de la aplicación que es necesario en la creación del objeto DatabaseHelper dentro del método open. La llamada a getwritabledatabase devuelve un objeto de tipo SQLiteDatabase con acceso de lectura/escritura que almacenamos en el atributo db_compra. El motivo de devolver una referencia del mismo objeto (this) es para permitir una inicialización encadenada, es decir, que el objeto devuelto por la llamada de este método se pase como parámetro de otro método. El método close cierra la conexión iniciada previamente, liberando así los recursos abiertos. Para concluir la implementación de esta clase, debemos incluir los métodos de inserción, eliminación y consulta de productos almacenados en la tabla productos. Como quizás se pueda intuir a estas alturas, para hacer esto debemos hacer uso del objeto SQLiteDatabase obtenido en el método open y almacenado en el atributo db_compra. Este objeto tiene métodos insert, delete y query, entre otros, que facilitan la labor de gestión de las sentencias SQL, abstrayéndolo del mismo. El código de estas funciones se lista a continuación: public long crearelemento(string producto, int cantidad) { ContentValues valoresproducto = new ContentValues(); valoresproducto.put(clave_producto, producto); valoresproducto.put(clave_cantidad, cantidad); return this.db_compra.insert(database_tabla, null, valoresproducto); public boolean borrarelemento(long rowid) { return this.db_compra.delete(database_tabla, CLAVE_ID + "=" + rowid, null) > 0; public Cursor obtenertodoselementos() { return this.db_compra.query(database_tabla, COLUMNAS_CONSULTA, null, null, null, null, null); public Cursor obtenerelemento(long rowid) throws SQLException { Cursor mcursor = this.db_compra.query(true, DATABASE_TABLA, COLUMNAS_CONSULTA, CLAVE_ID + "=" + rowid, null, null, null, null, null); if (mcursor!= null) { mcursor.movetofirst(); return mcursor; public boolean actualizarelemento(long rowid, String producto, int cantidad) { ContentValues args = new ContentValues(); args.put(clave_producto, producto); -4-

args.put(clave_cantidad, cantidad); return this.db_compra.update(database_tabla, args, CLAVE_ID + "=" + rowid, null) > 0; La explicación de lo que realiza cada uno de los métodos es la siguiente: 1. public long crearelemento(string producto, int cantidad). El método inserta en la tabla productos el elemento cuyos datos se pasan por parámetro y se retorna el identificador de este elemento. Los valores del elemento se almacenan en un objeto ContentValues en la forma clave-valor que posteriormente recibe el método insert cuyos parámetros son: la tabla donde almacenar el elemento, la lista de columnas con valores nulos (es opcional y puede ser null) y un objeto ContentValues donde, la clave es el nombre de la columna de la tabla y el valor, el elemento a almacenar en dicha columna. 2. public boolean borrarelemento(long rowid). Borra el elemento cuyo identificador es especificado por el parámetro, y devuelve true si se ha borrado con éxito o false en caso contrario. Para hacer esto, se ejecuta el método delete del objeto SQLiteDatabase que recibe por parámetro la tabla, y la clausula WHERE que ha de cumplir el elemento o los elementos que se van a eliminar. Si se pasara null se eliminarían todas las filas de la tabla. El tercer argumento es opcional. 3. public Cursor obtenertodoselementos(). Este método devuelve un objeto Cursor sobre todos los elementos de la lista de la compra. La consulta se realiza a través del método query que recibe una extensa lista de parámetros: boolean distinct: true si queremos que no haya duplicados en las filas obtenidas. String table: nombre de la tabla sobre la que se realiza la consulta. String [] columns: columnas de las que queremos obtener la información. String selection: condiciones que deben cumplir las filas seleccionadas, codificadas como la clausula WHERE. String [] selectionargs: La cadena selection anterior se puede parametrizar, utilizando el símbolo? que será sustituido por los valores contenidos en este vector. Es útil para preformatear las cadenas de selección y utilizar los datos recibidos por parámetro. String groupby: filtro para establecer como agrupar las filas. String having: si la clausula groupby es usada, la clausula having establece un filtro sobre qué grupo de filas deben aparecer en la consulta. String orderby: establece como ordenar las filas. String limit: establece el número máximo de filas a devolver por el Cursor, si no se indica no hay ningún límite. 4. public Cursor obtenerelemento(long rowid). Similar al anterior, pero en este caso se usa el parámetro selection para devolver la fila que coincida con el identificador pasado por parámetro. 5. public boolean actualizarelemento(long rowid, String producto, int cantidad). Es muy similar al método crearelemento. En este caso se hace uso del método update que recibe los mismos parámetros que insert, pero permutados: nombre de la tabla, objeto ContentValues con los nuevos valores a modificar, clausula WHERE y clausula WHERE parametrizada (con los símbolos?). -5-

Aquí finaliza la descripción de la clase utilitaria para la base de datos donde almacenaremos la lista de productos pendientes de compra. A continuación se explicará como se ha de codificar las dos actividades de las que se compone esta aplicación ListaCompra. Actividad Una vez la aplicación ListaCompra esté finalizada, puede probar a modificar el valor de la constante VERSION definida en esta clase. Verá que al ejecutar nuevamente la aplicación en el emulador, todos los elementos de la lista se eliminarán. Un buen ejercicio sería modificar el método onupdate para que cuando se produzca una actualización no se pierdan los datos almacenados. Actividad principal: ListaCompraActivity El diseño de esta actividad se compone de dos tareas: el diseño de la interfaz gráfica en el correspondiente fichero xml de layout, y la codificación de la clase Java que heredará de ListActivity. Empezaremos mostrando cuál es el código xml de la interfaz de esta actividad que se ha codificado en el fichero main.xml: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <Button android:id="@+id/ańadir" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/ańadir" /> <TextView android:id="@android:id/empty" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/no_elements"/> <ListView android:id="@android:id/list" android:layout_width="fill_parent" android:layout_height="wrap_content" > </ListView> </LinearLayout> Hasta el momento veníamos obviando el diseño de la interfaz gráfica ya que se proponía como ejercicio para el lector. En este caso se muestra para destacar varias peculiaridades de esta aplicación. El gestor de distribución es un componente LinearLayout que contiene 3 elementos. El primero de ellos es un Button que se utilizará para llamar a la actividad que añade nuevos productos a la compra (nada de peculiar en esto). El siguiente elemento es un TextView que mostrará el mensaje de No se han añadido productos en caso de que la lista de la compra esté vacía. Para lograr esto, el id de este elemento debe ser @andorid:id/empty. Si hubiera elementos que mostrar en la lista, el sistema Android buscaría un -6-

elemento cuyo identificador coincidiera con @android:id/list que es justo el identificador definido para el tercer elemento del layout, el ListView. Estos identificadores de elementos están predefinidos y pertenecen al espacio de nombres de Android. La clase ListaCompraActivity debe heredar de ListActivity. El método oncreate debe abrir una conexión a la base de datos para rellenar la lista de la compra y establecer el listener del botón Añadir que abrirá la actividad NuevoProductoActivity. A continuación se muestra este código: public class ListaCompraActivity extends ListActivity { // Constantes para identificar diferentes acciones a lanzar por un Intent. private static final int ACTIVITY_CREAR=0; // Atributos privados private ListaCompraDatabaseAdapter dbadapter; private Button bańadir ; public void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); dbadapter = new ListaCompraDatabaseAdapter(this); dbadapter.open(); rellenarlista(); bańadir = (Button)findViewById(R.id.ańadir ); bańadir.setonclicklistener(new OnClickListener(){ public void onclick(view v) { ańadirproducto(); ); //end_oncreate //end_class Veamos ahora como rellenar la vista de la actividad con los datos de la base de datos, esto es, como implementar el método rellenarlista(): private void rellenarlista() { Cursor comprascursor = dbadapter.obtenertodoselementos(); startmanagingcursor(comprascursor); // Array para especificar las columnas que se mostrarán en el ListView (solo Producto) String[] desde = new String[]{ListaCompraDatabaseAdapter.CLAVE_PRODUCTO; // Array con los id de los elementos de layout con los que se enlazarán los datos de la consulta int[] hacia = new int[]{r.id.tvproducto; // Creamos un objeto SimpleCursorAdapter que enlazará el resultado de la consulta con el ListView SimpleCursorAdapter compras = new SimpleCursorAdapter(this, R.layout.producto_row, comprascursor, desde, hacia); setlistadapter(compras); En primer lugar se obtiene un cursor sobre todos los elementos de la base de datos llamando al método obtenertodoselementos y seguidamente se pasa como parámetro a startmanagingcursor. Este método lo que hace es gestionar de forma automática el cursor con respecto al ciclo de vida de la actividad. Si la actividad es pausada, el cursor libera los recursos y en el momento que la actividad pase a primer plano se recupera la conexión con la base de datos. Este método se ha declarado como obsoleto, a partir de la versión 3.0 (HONEYCOMB) la forma preferente es usar la clase CursorLoader -7-

a través de un objeto LoaderManager. Además estas clases están disponibles en plataformas antiguas por medio del paquete de compatibilidad de Android. Más información acerca de Loaders en: http://developer.android.com/guide/topics/fundamentals/loaders.html Nota Más adelante, una vez se haya finalizado la aplicación, se puede modificar la llamada a startmanagingcursor por un código más apropiado que use un CursorLoader. Los vectores desde y hacia se utilizan para enlazar el resultset (las filas resultado de la consulta sql) del Cursor con los elementos de la interfaz gráfica, es decir, qué columnas del resultset se van a mostrar en qué componente del layout. Por tanto debemos crear un nuevo fichero de layout con el fin de visualizar cada uno de las filas de esta lista (recordemos como personalizamos el layout de los elementos de un ListView en la aplicación EquiposFutbol). Estos vectores se han diseñado de la siguiente manera: String[] desde: contiene los nombres de las columnas que se van a visualizar, de momento solo el nombre del producto. int[] hacia: contiene los identificadores de los elementos del layout en los que se va a mostrar la información de la consulta, en este caso solo un TextView para mostrar el nombre del producto. Solo faltaría crear un objeto Adapter para asociarlo al ListView de la actividad, usaremos un SimpleCursorAdapter, aunque este constructor también está obsoleto. Actividad Diseña el fichero de layout producto_row.xml necesario para visualizar el nombre del producto en el ListView. Más adelante, una vez finalizada la aplicación, modifica el código anterior para que se visualice también el valor de la cantidad de cada producto. La actividad aún está incompleta. Debemos dar respuesta al evento de pulsación sobre el botón que hemos colocado en la interfaz. Este botón debe abrir una actividad que añada un nuevo producto a la lista de la compra. Una vez iniciada la actividad se debe esperar respuesta, si se ha añadido el producto con éxito o no, por tanto se iniciará la nueva actividad con la llamada a startactivityforresult. La llamada a esta función requiere de un parámetro, un número entero mayor o igual que 0 en el que se informe de la acción que se lleva acabo y que será retornado en el método onactivityresult. Esto es de utilidad ya que permitirá dar una respuesta personalizada según que acción, cuando se obtienen los resultados en el método onactivityresult. Con todo lo descrito anteriormente, la implementación de este método será: protected void ańadirproducto(){ Intent i = new Intent(this, NuevoProductoActivity.class); startactivityforresult(i, ACTIVITY_CREAR); -8-

Para dar respuesta a la actividad iniciada, debemos sobrescribir el método onactivityresult en el que se comprobará si se ha añadido con éxito un nuevo producto, y en ese caso rellenar de nuevo la lista de la compra. protected void onactivityresult(int requestcode, int resultcode, Intent intent) { super.onactivityresult(requestcode, resultcode, intent); if(resultcode==activity.result_ok) rellenarlista(); Con esto damos por finalizada la actividad principal de la aplicación ListaCompra, solo falta proveer el mecanismo adecuado para poder añadir elementos que comprar a nuestra lista. Pasamos a describir la implementación de la actividad NuevoProductoActivity. Actividad secundaria: NuevoProductoActivity Esta actividad se encarga de añadir nuevos elementos a la base de datos. Debe pedir al usuario que introduzca el nombre del producto y la cantidad del mismo. Actividad Diseña la interfaz gráfica en el fichero de layout nuevo_producto.xml. La interfaz contendrá un elemento Button y dos elementos TextView, uno de ellos, el correspondiente a la cantidad, con el atributo android:inputtype= number para que solo se puedan introducir números naturales (no negativos). El método oncreate de esta actividad debe obtener las referencias a los elementos del layout, iniciar la conexión con la base de datos y establecer el listener del botón aceptar para salvar los datos del nuevo producto. public class NuevoProductoActivity extends Activity { // Manejador de la base de datos private ListaCompraDatabaseAdapter dbadapter; // Atributos para referenciar elementos del layout private EditText nombre_producto; private EditText cantidad; private Button baceptar; protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.nuevo_producto); dbadapter = new ListaCompraDatabaseAdapter(this); dbadapter.open(); nombre_producto = (EditText)findViewById(R.id.etProducto); cantidad = (EditText)findViewById(R.id.etCantidad); baceptar = (Button)findViewById(R.id.bAceptar); baceptar.setonclicklistener(new OnClickListener(){ public void onclick(view v) { if(salvarproducto()){ setresult(activity.result_ok); -9-

); //end_oncreate //end_class finish(); Nótese que los identificadores para obtener los elementos de layout pueden variar en función de los que haya especificado en su propio fichero. Ya debe estar suficientemente familiarizado con el código anterior. Resaltaremos que el método onclick del botón Aceptar llama al método salvarproducto que devuelve un valor boolean para informar del éxito de la inserción en la base de datos. Se informa del éxito (true) de la actividad con el método setresult y la constante RESULT_OK de la clase Activity. Este valor será informado como parámetro del método onactivityresult. El método salvarproducto obtiene los datos de la interfaz y llama al método crearelemento del objeto manejador de la base de datos. El único punto conflictivo que puede ocurrir en este método es que se intente insertar en la base de datos valores nulos, por lo que se deberá manejar adecuadamente. El código del método es el siguiente: protected boolean salvarproducto(){ boolean exito = false; try { String producto = this.nombre_producto.gettext().tostring(); int cantidad = Integer.valueOf(this.cantidad.getText().toString()); this.dbadapter.crearelemento(producto, cantidad); exito = true; catch (NumberFormatException e) { Toast.makeText(this, "Es obligatorio introducir la cantidad", Toast.LENGTH_LONG); return exito; Actividad La implementación anterior permite insertar un nuevo producto sin nombre. Modifica el código para que esto no ocurra. -10-