El tutor de nuestro curso online de Desarrollo de Aplicaciones para Android, Víctor Ramírez Las,…
Proyecto ejemplo de App Android con bbdd SQLite
4.
Proyecto ejemplo de App Android con bbdd SQLite
Tras explicar las operaciones CRUD en un sistema de base de datos SQLite, vamos a desarrollar una sencilla Aplicación con Android Studio que nos muestre de forma práctica su implementación.
Operaciones CRUD: son las operaciones básicas en un sistema de persistencia de datos, es decir: crear/insertar, leer/consultar, actualizar o borrar datos. Se les suele conocer por su acrónimo en inglés CRUD (create, read, update y delete).
Para ello, crearemos un proyecto con Android Studio donde se gestionarán los registros de una base de datos SQLite desde un sencillo formulario.
La aplicación permitirá dar de alta, consultar y borrar comentarios asociados a distintos nombres de usuarios. Podremos elegir cada comentario de una lista que crearemos utilizando el componente gráfico Spinner.
En la parte derecha puedes ver su funcionamiento.
Este proyecto, como es habitual, lo describiremos en dos publicaciones, ésta, donde podrás además descargar el proyecto y una posterior en formato video con explicaciones detalladas del código.
Estructura del Proyecto
El proyecto constara de los siguientes elementos:
- activity_main: formado por un layout de tipo LinearLayout, en el que distribuiremos los distintos elementos gráficos.
- MainActivity: Activity principal de la aplicación, que implementara la lógica de funcionamiento de la aplicación, incluyendo los controladores de eventos de los elementos de la interfaz.
- Comentario: clase java sencilla que nos servirá para representar los elementos que almacenamos en la base de datos
- MyOpenHelper: implementación de SQLiteOpenHelper basada en la que ya vimos en una publicación anterior y que ampliaremos con varias funciones auxiliares para simplificar el código de MainActivity.
En la siguiente imagen, se podrá apreciar cómo quedaría finalmente la estructura de elementos que intervienen en el proyecto (vista Android en el IDE Android Studio):
Descripción del código fuente
Vamos a analizar el código fuente de los distintos componentes del proyecto.
Para empezar mostramos la interfaz de usuario definida en el fichero activity_main.xml:
Como vemos esta compuesta por un panel superior que nos permitirá crear nuevos comentarios, un Spinner en el que se mostrarán los comentarios existentes y mediante el cual podremos seleccionar uno de ellos, y finalmente un panel inferior que nos mostrará los datos del comentario seleccionado. Cada zona tiene además su botón correspondiente para la acción a realizar.
Mostramos a continuación el contenido del fichero de layout xml:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.academiaandroid.proyectodatos.MainActivity" android:orientation="vertical" android:weightSum="1"> <TextView android:text="Crea un nuevo comentario" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtCrear" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPersonName" android:text="Nombre" android:ems="10" android:id="@+id/editNombre" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textMultiLine" android:ems="10" android:id="@+id/editComentario" android:layout_weight="0.34" android:text="Comentario" /> <Button android:text="Crear" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnCrear" /> <TextView android:text="Seleccione un comentario" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtVer" /> <Spinner android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/spinComentarios" /> <Button android:text="Ver" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnVer" /> <TextView android:text="Ver comentario" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/txtEliminar" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textPersonName" android:ems="10" android:id="@+id/txtNombre" /> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="textMultiLine" android:ems="10" android:id="@+id/txtComentario" android:layout_weight="0.41" /> <Button android:text="Eliminar" android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/btnEliminar" /> </LinearLayout> |
Vamos a analizar a continuación la clase Comentario.
La clase cuenta con los mismos atributos que representan un comentario en la base de datos:
1 2 3 4 5 6 7 8 9 |
package com.academiaandroid.proyectodatos; //Clase para representar un comentario public class Comentario { //Campos correspondientes a la base de datos int id; String nombre; String comentario; |
El constructor de la clase nos permite crear e inicializar los atributos de un comentario:
1 2 3 4 5 6 7 |
//Constructor public Comentario(int _id,String _nombre,String _comentario){ id=_id; nombre=_nombre; comentario=_comentario; } |
La clase toString sera necesaria para mostrar los comentarios en el Spinner, en nuestro caso sólo mostraremos el nombre para seleccionar:
1 2 3 4 5 6 |
//Represetacion del objeto como cadena de texto @Override public String toString() { return nombre; } |
Para terminar disponemos de 3 métodos para acceder a cada uno de los atributos de la clase:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Metodos de acceso a cada atribito de la clase public int getId(){ return id; } public String getNombre(){ return nombre; } public String getComentario(){ return comentario; } } |
Vamos a continuar describiendo el contenido de la clase MyOpenHelper.
Partiremos de los mismos elementos que ya mostramos en el apartado 5.2 de este tema, en el que vimos el código que creaba la base de datos en el dispositivo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
package com.academiaandroid.proyectodatos; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; import android.widget.CursorAdapter; import android.widget.SimpleCursorAdapter; import java.util.ArrayList; import java.util.List; public class MyOpenHelper extends SQLiteOpenHelper { private static final String COMMENTS_TABLE_CREATE = "CREATE TABLE comments(_id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, comment TEXT)"; private static final String DB_NAME = "comments.sqlite"; private static final int DB_VERSION = 1; private SQLiteDatabase db; public MyOpenHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); db=this.getWritableDatabase(); } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(COMMENTS_TABLE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } |
A este código inicial añadiremos dos funciones para insertar y eliminar comentarios, que si nos fijamos simplemente incluyen el código de inserción y borrado que vimos en su momento, pero ejecutado a partir de unos parámetros que enviaremos desde la interfaz de usuario.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
//Insertar un nuevo comentario public void insertar(String nombre,String comentario){ ContentValues cv = new ContentValues(); cv.put("user", nombre); cv.put("comment", comentario); db.insert("comments", null, cv); } //Borrar un comentario a partir de su id public void borrar(int id){ String[] args = new String[]{String.valueOf(id)}; db.delete("comments", "_id=?", args); } |
Finalmente añadiremos una función que ejecutará un select tal y como lo vimos en su momento, y a continuación recorrerá los distintos resultados creando objetos de la clase Comentario y almacenándolos en un array.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
//Obtener la lista de comentarios en la base de datos public ArrayList<Comentario> getComments(){ //Creamos el cursor ArrayList<Comentariolista=new ArrayList<Comentario>(); Cursor c = db.rawQuery("select _id, user,comment from comments", null); if (c != null && c.getCount()>0) { c.moveToFirst(); do { //Asignamos el valor en nuestras variables para crear un nuevo objeto Comentario String user = c.getString(c.getColumnIndex("user")); String comment = c.getString(c.getColumnIndex("comment")); int id=c.getInt(c.getColumnIndex("_id")); Comentario com =new Comentario(id,user,comment); //Añadimos el comentario a la lista lista.add(com); } while (c.moveToNext()); } //Cerramos el cursor c.close(); return lista; } } |
Finalmente la clase MainActivity contiene la lógica principal de la aplicación que detallamos a continuación:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
package com.academiaandroid.proyectodatos; import android.app.Activity; import android.content.Context; import android.database.Cursor; import android.os.Bundle; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.Button; import android.widget.CursorAdapter; import android.widget.EditText; import android.widget.Spinner; import android.widget.SpinnerAdapter; import android.widget.Switch; import android.widget.TextView; import java.util.ArrayList; |
En primer lugar vemos que la clase implementa las interfaces correspondientes a la gestión de eventos de los botones y el Spinner (un poco mas abajo veremos cómo se implementan).
El código continua con la declaración de los elementos gráficos, así como del array de comentarios y el objeto Comentario que utilizaremos para acceder al comentario seleccionado en el Spinner.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public class MainActivity extends Activity implements View.OnClickListener,AdapterView.OnItemSelectedListener { //Declaramos los elementos de la interfaz private Button btnCrear; private Button btnVer; private Button btnEliminar; private EditText editNombre; private EditText editComentario; private EditText txtNombre; private EditText txtComentario; //Declaración del spinner y su Adapter private Spinner spinComentarios; private ArrayAdapter spinnerAdapter; //Lista de comentarios y comentario actual private ArrayList<Comentariolista; private Comentario c; //Controlador de bases de datos private MyOpenHelper db; |
En el método onCreate() inicializamos como siempre los elementos gráficos y los asociamos a su manejador de eventos:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Inicializamos los elementos de la interfaz editNombre=(EditText) findViewById(R.id.editNombre); editComentario=(EditText)findViewById(R.id.editComentario); txtNombre=(EditText) findViewById(R.id.txtNombre); txtComentario=(EditText)findViewById(R.id.txtComentario); //Los elementos del panel inferior no seran editables txtNombre.setEnabled(false); txtComentario.setEnabled(false); btnCrear=(Button)findViewById(R.id.btnCrear); btnVer=(Button)findViewById(R.id.btnVer); btnEliminar=(Button)findViewById(R.id.btnEliminar); btnCrear.setOnClickListener(this); btnVer.setOnClickListener(this); btnEliminar.setOnClickListener(this); |
También iniciamos el controlador de la base de datos, obtenemos la lista de comentarios y creamos el Adapter que nos servirá para mostrar los comentarios del array como elementos seleccionables en el Spinner:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//Iniciamos el controlador de la base de datos db=new MyOpenHelper(this); //Iniciamos el spinner y la lista de comentarios spinComentarios=(Spinner) findViewById(R.id.spinComentarios); lista=db.getComments(); //Creamos el adapter y lo asociamos al spinner spinnerAdapter=new ArrayAdapter(this,android.R.layout.simple_spinner_dropdown_item,lista); spinComentarios.setAdapter(spinnerAdapter); spinComentarios.setOnItemSelectedListener(this); } |
En el método onClick() implementamos las funciones de cada botón, se han incluido comentarios en el código para explicar cada paso de la inserción, selección y borrado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
@Override public void onClick(View v) { //Acciones de cada boton switch(v.getId()){ case R.id.btnCrear: //Insertamos un nuevo elemento en base de datos db.insertar(editNombre.getText().toString(),editComentario.getText().toString()); //Actualizamos la lista de comentarios lista=db.getComments(); //Actualizamos el adapter y lo asociamos de nuevo al spinner spinnerAdapter=new ArrayAdapter(this,android.R.layout.simple_spinner_dropdown_item,lista); spinComentarios.setAdapter(spinnerAdapter); //Limpiamos el formulario editNombre.setText(""); editComentario.setText(""); break; case R.id.btnVer: //Si hay algun comentario seleccionado mostramos sus valores en la parte inferior if(c!=null) { txtNombre.setText(c.getNombre()); txtComentario.setText(c.getComentario()); } break; case R.id.btnEliminar: //Si hay algun comentario seleccionado lo borramos de la base de datos y actualizamos el spinner if(c!=null) { db.borrar(c.getId()); lista = db.getComments(); spinnerAdapter = new ArrayAdapter(this, android.R.layout.simple_spinner_dropdown_item, lista); spinComentarios.setAdapter(spinnerAdapter); //Limpiamos los datos del panel inferior txtNombre.setText(""); txtComentario.setText(""); //Eliminamos el Comentario actual puesto que ya no existe en base de datos c=null; } break; } } |
Finalmente la función onItemSelected() se ejecutará cuando seleccionemos en el spinner un nuevo comentario. Como podemos observar en ella, simplemente comprobaremos que hay comentarios en la lista, y si los hay, asociaremos el comentario seleccionado al objeto c (de tipo Comentario) que representa el comentario actual.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
//Controlador de elemento seleccionado en el spinner @Override public void onItemSelected(AdapterView<?parent, View view, int position, long id) { if (parent.getId() == R.id.spinComentarios) { //Si hay elementos en la base de datos, establecemos el comentario actual a partir del //indice del elemento seleccionado en el spinner if(lista.size()>0) { c = lista.get(position); } } } @Override public void onNothingSelected(AdapterView<?parent) { } } |
Descarga del proyecto
Para descargar el código de esta aplicación pulsa aquí:
Download